Translate

sábado, 9 de diciembre de 2023

Manejo de memoria en Rust



Los programas asignan memoria de dos maneras:

stack: Área continua de memoria para variables locales.

Los valores tienen tamaños fijos conocidos en el momento de la compilación.

Extremadamente rápido: basta con mover un puntero de pila.

Fácil de administrar: sigue llamadas a funciones.

Gran recuerdo de la localidad.


heap: almacenamiento de valores fuera de las llamadas a funciones.

Los valores tienen tamaños dinámicos determinados en tiempo de ejecución.

Ligeramente más lento que la pila: se necesita algo de contabilidad.

No hay garantía de localidad de memoria.


Veamos un ejemplo: La creación de una cadena coloca metadatos de tamaño fijo en el stack y datos de tamaño dinámico, la cadena real, en el heap:


fn main() {

    let s1 = String::from("Hello");

}




Una cadena está respaldada por un Vec, por lo que tiene capacidad y longitud y puede crecer si es mutable mediante reasignación en el heap.

Podemos inspeccionar el diseño de la memoria con Rust pero esto no es seguro.

fn main() {
    let mut s1 = String::from("Hello");
    s1.push(' ');
    s1.push_str("world");
    // DON'T DO THIS AT HOME! For educational purposes only.
    // String provides no guarantees about its layout, so this could lead to
    // undefined behavior.
    unsafe {
        let (ptr, capacity, len): (usize, usize, usize) = std::mem::transmute(s1);
        println!("ptr = {ptr:#x}, len = {len}, capacity = {capacity}");
    }
}