Revisión de la memoria de programas

Los programas asignan memoria de dos formas:

  • Stack: Zona de memoria continua para las variables locales.

    • Los valores tienen tamaños fijos conocidos en tiempo de compilación.
    • Muy rápida: mueve el stack pointer.
    • Fácil de gestionar: sigue las llamadas de funciones.
    • Excelente localidad de memoria.
  • Heap: almacenamiento de valores fuera de las llamadas de funciones.

    • Los valores tienen tamaños dinámicos determinados en runtime.
    • Ligeramente más lento que el stack: requiere cierta trazabilidad.
    • No se puede asegurar la localidad de la memoria.

Ejemplo

Al crear un String, los metadatos de tamaño fijo se colocan en la stack y los datos de tamaño dinámico (la cadena real) en el heap:

fn main() {
    let s1 = String::from("Hola");
}
StackHeaps1ptrHellolen5capacity5
This slide should take about 5 minutes.
  • Menciona que un String está respaldado por un Vec, por lo que tiene capacidad y longitud y, si es mutable, puede crecer mediante reasignación en el heap.

  • Si los alumnos lo preguntan, puedes mencionar que la memoria subyacente recibe una asignación de heap mediante el Asignador del Sistema y que se pueden implementar asignadores personalizados mediante el Allocator API.

Más información

We can inspect the memory layout with unsafe Rust. However, you should point out that this is rightfully unsafe!

fn main() {
    let mut s1 = String::from("Hola");
    s1.push(' ');
    s1.push_str("mundo");
    // ¡NO HAGÁIS ESTO EN CASA! Solo con fines educativos.
    // La cadena no proporciona garantías sobre su diseño, por lo que podría desencadenar
    // un comportamiento indefinido.
    unsafe {
        let (ptr, capacity, len): (usize, usize, usize) = std::mem::transmute(s1);
        println!("ptr = {ptr:#x}, longitud = {len}, capacidad = {capacity}");
    }
}