Revisão da Memória de Programa
Os programas alocam memória de duas maneiras:
-
Pilha: Área contínua de memória para variáveis locais.
- Os valores têm tamanhos fixos conhecidos em tempo de compilação.
- Extremamente rápida: basta mover um ponteiro de pilha.
- Fácil de gerenciar: segue chamadas de função.
- Ótima localidade de memória.
-
Heap: Armazenamento de valores fora das chamadas de função.
- Valores possuem tamanhos dinâmicos determinados em tempo de execução.
- Ligeiramente mais devagar que a pilha: é necessário um pouco de gerenciamento.
- Sem garantias de localidade de memória.
Exemplo
A criação de uma String
coloca metadados de tamanho fixo na pilha e dados dinamicamente dimensionados - a string propriamente dita - no heap:
fn main() { let s1 = String::from("Olá"); }
-
Mencione que uma
String
é suportada por umVec
, portanto ela tem um tamanho e capacidade e pode crescer se for mutável por meio de realocação no heap. -
Se os alunos perguntarem sobre isso, você pode mencionar que a memória subjacente é alocada no heap usando o System Allocator e os alocadores personalizados podem ser implementados usando a API Allocator.
Mais para Explorar
Podemos inspecionar o layout da memória com Rust inseguro (unsafe
). No entanto, você deve apontar que isso é legitimamente inseguro!
fn main() { let mut s1 = String::from("Olá"); s1.push(' '); s1.push_str("mundo"); // NÃO FAÇA ISSO EM CASA! Somente com propósito educacional. // String não fornece nenhuma garantia sobre o seu layout, então isso pode causar // um comportamento indefinido. unsafe { let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1); println!("capacidade = {capacity}, ptr = {ptr:#x}, compr = {len}"); } }