ASIGNACION DINAMICA DE MEMORIA: INTRODUCCION







Conceptos básicos.

Tiempo compartido y reparto de memoria

La forma en que se ejecuta un programa en una computadora se parece bastante a dos personas que tuvieran encomendada una tarea, como sumar una larga lista de números. Una de las personas tiene un cuaderno (la memoria de la computadora), en el que están apuntados los datos que hay que sumar, y en el que habrá que escribir los resultados. La otra persona tiene una calculadora, y va preguntando lo que tiene que hacer al encargado del cuaderno. A medida que hace las cuentas, indica al del cuaderno los resultados. El usuario es el que va escribiendo en el cuaderno lo que hay que hacer, y luego la otra pareja se encarga de realizar las tareas indicadas por el usuario. Por cierto, y aunque no se le vea, hay una tercera persona: es el sistema operativo, que es quien dice a la pareja cuaderno-calculadora cosas tan importantes como que empiece a trabajar, que se detenga cuando acabe, que espere un momentito porque le traen una hoja de papel con información de última hora [un disquette], etc.
Con el paso del tiempo, tanto el encargado de las cuentas (el procesador) como el encargado del cuaderno (la memoria) se han vuelto muy rápidos. De hecho, hemos observado que en muchas ocasiones nosotros tardamos mucho en escribir los datos en el cuaderno, y la pareja cuaderno-ordenador queda a la espera de tareas: están perdiendo el tiempo. Para evitar esto, nos ponemos de acuerdo con el usuario de al lado, que tiene cosas por hacer, y le permitimos que conecte su propio ordenador al nuestro. Como somos generosos, le decimos que él puede hacer uso de nuestro ordenador en segundos pares, y nosotros usaremos los impares. O mejor, le decimos que él puede hacer uso de los milisegundos pares, y nosotros usaremos los impares. El ordenador invertirá en atender al vecino el tiempo que antes pasaba esperando nuestras peticiones, y de este modo, sin pérdida de velocidad por nuestra parte, aprovecharemos mejor la máquina. Este proceso se denomina "de tiempo compartido".
¿Cómo se ha organizado la pareja cuaderno-calculadora? Fácilmente: la mitad del cuaderno se destina a nosotros, y la otra mitad al vecino. Para que no haya confusiones, la tercera persona de que hablabamos (el sistema operativo) se asegura de que nosotros sólo podamos escribir en nuestras páginas, y de que el vecino sólo pueda escribir en las suyas. A veces nos ponemos de acuerdo y reservamos unas cuantas páginas que vamos a compartir con el vecino; a esto se le llama comunicación entre procesos. Pero cada programa o proceso tiene asignada una zona propia de memoria, que le ha sido asignada para el sistema operativo.
Sigamos adelante: aun cuando tanto nosotros como el vecino nos esforzamos por dar tareas al ordenador, éste sigue esperando sin hacer nada la mayor parte del tiempo. Por tanto, tiene sentido permitir su utilización a más personas, asignando a cada una ciertas páginas del cuaderno; el sistema operativo irá prestando atención a las distintas tareas, que se ejecutarán aparentemente a la vez. En realidad, yo sólo estoy utilizando un milisegundo cuando me hace falta, pero no aprecio pérdida de velocidad. En mi ordenador se ejecutan múltiples programas, de los que algunos son míos y otros no. Cada programa tiene asignada una zona de memoria propia; sólo ése programa puede escribir en ella, y ése programa sólo puede escribir en esa zona, pero no en la memoria de los demás programas. Esta normativa, que impone el sistema operativo, recibe el nombre de protección de memoria.

Uso de la memoria asignada a una aplicación - reserva y liberación de memoria en el cúmulo

¿De qué forma se utiliza la memoria asignada a una aplicación? Básicamente, se descompone en tres zonas: pila, cúmulo y código.



Asignación y liberación de memoria.
Las variables dinámicas se crean y destruyen al arbitrio del programador. El objetivo que se persigue es racionalizar la utilización de un recurso escaso, la memoria RAM. El método que se emplea sigue los pasos indicados a continuación:



Fragmentación del cúmulo.
Existen dos grandes bloques de estructuras dinámicas de datos:



Entonces cabe pensar que no tiene sentido construir estructuras no lineales, porque son menos eficientes. Pero la realidad es distinta: a medida que se crean y destruyen variables dinámicas, el cúmulo va siendo "invadido" por bloques. Algunos de estos bloques se destruyen (se libera su memoria) al cabo de unos instantes, pero otros permanecen, porque la información que contienen es precisa a lo largo de un periodo de tiempo mayor. Entonces la memoria disponible ya no forma un único bloque libre, como al principio de la ejecución del programa, sino múltiples bloques de dimensiones menores. Cuanto mayor sea el número de variable dinámicas de cierta duración que haya en el programa, más fragmentado estará el cúmulo. Y aquí surge el problema: los bloques que utilizan las estructuras dinámicas lineales suelen ser de gran tamaño, porque el número de elementos almacenados en el bloque es elevado. Cuanto mayor sea el bloque necesario para albergar una estructura lineal dinámica, más probabilidades hay de que no sea posible encontrar espacio para él. No es que nos hayamos quedado sin memoria: es que no hay espacio contiguo suficiente. Resumiendo, la fragmentación del cúmulo puede hacer imposible utilizar variables dinámicas lineales. Pero este problema no va a existir en las variables dinámicas no lineales, porque éstas están formadas por múltiples bloques, de dimensiones necesariamente menores a igualdad de información total almacenada. Entonces, aún cuando el cúmulo esté notablemente fragmentado, una estructura dinámica no lineal tiene grandes probabilidades de ir hallando pequeños bloques libres, suficientes para albergar sus elementos y adecuados para formar finalmente toda la cadena necesaria.
Por esta razón, es muy frecuente emplear estructuras dinámicas no lineales cuando se prevé que puede aparecer fragmentación en el cúmulo como consecuencia de una gran cantidad de creaciones y destrucciones de variables, o si la memoria no es excesivamente abundante.
En las próximas secciones abordaremos la construcción de variables dinámicas, tanto lineales como no lineales. Nuestro objetivo es optimizar el uso de la memoria disponible en el cúmulo, y también mostrar ciertos métodos de trabajo de uso frecuente.