Bienvenidos sean a este post, hoy veremos la otra parte de la memoria.
En el post anterior hablamos sobre la primera seccion de la memoria mas conocida como stack o tambien como memoria baja o base, enumeramos algunas de sus caracteristicas y con cual tipos de datos trabaja pero hoy nos centraremos en la otra parte mas conocida como heap o tambien como memoria alta o extendida (dependiendo cuan viejo seas 😄) y algunas caracteristicas de esta son:
- Es mas lenta con respecto a stack
- Tiene el resto de la memoria disponible del equipo
- Los datos son mas persistentes
En el post anterior mencionamos que todos los tipos primitivos o basicos se asignan en el stack o la memoria baja y los que son mas complejos los ubicamos en el heap o memoria alta, aunque esto tambien puede modificarse para que stack maneje tipos complejos pero debemos usar apuntadores que vean las direcciones de la parte alta de memoria pero eso lo veremos mas adelante.
Al igual que en el caso anterior vamos a ver el siguiente codigo como ejemplo:
fn main
{
let f = 42;
let mi_ids: Vec<i64> = Vec::with_capacity(5);
}
Aqui tenemos una funcion que tendra un hibrido de variables, dado que tenemos una variable primitiva de tipo int y otra de tipo Vector, si volvemos a usar la tabla que vimos en el post anterior para representar los datos en memoria, veamos como seria:
Funcion | Direccion | Variable | Valor |
main | 1 | f | 42 |
main | 0 | mi_ids | (alguna instancia de Vector) |
Se estaran preguntando porque aparece las dos variables en la misma parte de la memoria, esto es debido a que el lenguaje en general las variables de tipo primitivo tendra el nombre de la variable y el valor de la misma pero en cambio las complejas tendra la variable en el stack pero sus datos estaran en el heap y desde el stack sera solamente un apuntador a estos valores, como dijimos los valores ubicados en esta seccion de memoria tienden a ser tomados como persistentes y no estan limitiados al ciclo de vida de una funcion.
Pero esto puede generar una serie de inconvenientes, porque ahora la informacion no sera borrada de la memoria tal como sucedia con los datos en stack y por lo tanto podemos saturar la memoria, para evitarlo ahora nosotros debemos encargarnos de eliminar estos datos «huerfanos» de la memoria pero esto nos generara huecos en la misma, si bien cuando volvamos a subir valores de variables el mismo sistema se encargara de reubicar la informacion en estos huecos para aprovechar la memoria, aunque el optimizador de memoria hoy funciona muy bien puede generar ciertos inconvenientes a la hora de leerlos.
Si bien en general los lenguajes a la hora de manipular objetos creados de clases emplea unos metodos especiales llamados constructores para asignar la estructura y los primeros datos en memoria tambien posee unos metodos llamados destructores que se encargan de limpiar la memoria una vez que el objeto es eliminado, esta es la verdadera parte que se encarga de mantener limpio nuestro heap tanto de informacion como de apuntadores.
En Rust la «destruccion» de un objeto se hace cuando el enlace queda fuera de rango (o scope) pero esto no quita que al igual que en otros lenguajes podemos definir nuestros propios destructores, para ello debemos utilizar el trait std::ops::Drop(), este contiene un solo metodo llamado drop que tambien es llamado cuando se alcanza la condicion anterior.
Nota: No se preocupen por los traits y otros temas que lo veremos mas adelante.
En resumen, hoy hemos visto la otra parte de la memoria, conocida como heap o memoria alta, sus caracteristicas, cuales son sus ventajas y desventajas con respecto a la anterior, tambien hemos visto como trabaja y algunas particularidades mas, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
