Está en la página 1de 5

GESTION DE MEMORIA 1

1. Introducción
Para ejecutar un proceso, éste debe encontrarse en memoria principal. Como hemos visto en el capítulo
anterior, para mejorar el aprovechamiento de la CPU, ésta se reparte entre varios procesos, por lo tanto,
también habrá que repartir la memoria principal.
A la parte del sistema operativo que se ocupa de gestionar la memoria se le denomina Gestor de
Memoria. Su cometido consiste en llevar la cuenta de las partes de memoria que se están utilizando y las
que están libres, así como de gestionar el traspase de información entre la memoria principal y la
secundaria cuando la memoria RAM no sea suficientemente grande para acoger a todos los procesos.
En este capítulo trataremos los distintos enfoques que hay en la gestión de memoria. Los algoritmos
varían desde el correspondiente a una simple máquina desnuda, hasta las estrategias de paginación y
segmentación.

2. Objetivos

Protección
Si varios procesos comparten la memoria principal, se debe asegurar que ninguno de ellos pueda
modificar posiciones de memoria de otro proceso.
Aunque la escritura de memoria tiene efectos más desastrosos, la lectura de memoria ajena tampoco
debe estar permitida, pues cada proceso debe mantener su privacidad. Debe disponerse de un sistema de
permisos de acceso que especifique los derechos que tiene cada proceso en el acceso a zonas de memoria
de otros procesos.

Compartimiento
El compartimiento de la memoria parece estar en contradicción con la protección, pero es que a menudo
también es necesario que varios procesos puedan compartir y actualizar estructuras de datos comunes,
por ejemplo, en un sistema de bases de datos. En otras ocasiones, lo que se requiere es compartir zonas
de código, por ejemplo, en rutinas de biblioteca, para no tener en memoria distintas copias de la misma
rutina. En este caso, se hace necesaria alguna protección para que un proceso no modifique
inadvertidamente el código de las rutinas.

Organización eficiente de la memoria


La memoria se debe organizar tanto física (jerarquía de memoria) como lógicamente (segmentos).
Debido al coste de la rápida memoria RAM, normalmente se necesita ampliarla con memoria secundaria
más barata (y más lenta), utilizando para ello dispositivos tales como discos o cintas magnéticas. Por el
contrario, también puede resultar conveniente añadir memoria de acceso más rápido que la RAM
principal, como es el caso de la memoria caché, en la que se mantienen los datos de acceso más
frecuente.
Si una gestión de memoria pudiera proporcionar varios espacios de direcciones, cada estructura lógica
podría ser una entidad independiente: un segmento. Esto sería ventajoso por varias razones, pues los
segmentos pueden compilarse y cargarse de forma independiente, teniendo cada uno de ellos sus propios
derechos de acceso (lectura, escritura, ejecución).

Reubicación de procesos
La multiprogramación requiere que varios procesos residan simultáneamente en memoria. Lo que no se
puede saber antes de llevarlo a memoria es la dirección absoluta en la que se va a cargar el proceso, por
lo que no es práctico utilizar direcciones absolutas en el programa. En su lugar, es preferible realizar
direccionamientos relativos para permitir que un programa pueda ser cargado y ejecutado en cualquier
parte de la memoria.

3. La gestión de memoria
Los sistemas de gestión de memoria pueden dividirse en dos clases: los que mueven los procesos entre
memoria principal y secundaria (intercambio y paginación), y los que no lo hacen. Tanto el intercambio
como la paginación son mecanismos originados por la insuficiencia de memoria principal para contener
todos los procesos en memoria simultáneamente. A medida que la memoria se vaya haciendo más barata,
puede que los argumentos en favor de unos u otros tipos de gestión vayan cambiando, aunque teniendo
en cuenta la ley de Parkinson: “Los programas tienden a expandirse hasta llenar la memoria que
los
contiene”, parece difícil que puedan cambiar radicalmente.
Pasemos a ver, en los siguientes apartados, las distintas técnicas de gestión de memoria.

3.1 Gestión de memoria sin intercambio


En los sistemas de gestión de memoria sin intercambio, la idea básica consiste en cargar el programa a
ejecutar en algún lugar de la memoria principal, donde permanece hasta que finaliza su ejecución,
momento en el que abandona el espacio de memoria utilizado.
Veamos a continuación las técnicas más habituales para los diferentes modelos de programación sin
intercambio de memoria.
a) Monoprogramación
El esquema de memoria más simple consiste en mantener la memoria ocupada con un único proceso.
Cuando se carga un programa que se hace cargo de toda la memoria y del control completo de la
máquina, se dice que el programa se
carga sobre una máquina desnuda, es decir, una máquina en la que solamente se ofrece el hardware
puro, sin ninguna ayuda software que lo recubra. Las máquinas desnudas se utilizaron de forma general
hasta principios de los años 60, y
actualmente se suelen
utilizar en sistemas empotrados de control.
Más tarde, a las máquinas desnudas se les añadió una especie de sistema operativo muy rudimentario al
que se le denominó monitor. Las funciones que ofrecía el monitor eran las estrictamente necesarias
para cargar un programa en memoria y controlar su ejecución, todo de forma muy manual y con una
completa supervisión del usuario.
La técnica actual más utilizada en los pequeños ordenadores es la que se muestra en la Figura 2. La
memoria está ocupada por el sistema operativo, que suele estar en RAM, y por el cargador inicial del
sistema operativo (IPL) y los drivers de dispositivos, que suelen estar en memoria ROM. El resto de la
memoria RAM queda disponible como área de usuario.
Cuando el sistema está organizado de esta manera (por ejemplo MS-DOS), sólo se ejecuta un proceso a la
vez. El usuario teclea un comando en el terminal, y el
sistema operativo carga el programa correspondiente de disco a memoria principal y lo ejecuta. Cuando
el programa termina, el sistema queda a la espera de que el usuario escriba otro comando, para cargar
otro programa en la misma zona de memoria que el anterior.

b) Multiprogramación con particiones fijas


Ya que, en general, es deseable que haya varios procesos de usuario residiendo en memoria al mismo
tiempo, se hace necesario considerar el problema de cómo asignar memoria disponible a varios de los
procesos que están en la cola de espera para ser traídos a memoria principal. Lo más inmediato y simple
es dividir la memoria en _ particiones (posiblemente de distinto tamaño), de tal forma que en cada
partición se mete un proceso, donde permanece hasta que finaliza su ejecución. Una vez terminado el
proceso, la partición queda libre para acoger
a un nuevo trabajo.
Con la llegada de la multiprogramación y este esquema de memoria aparecen algunos problemas y
cuestiones que deben solventarse, como la planificación de procesos a largo plazo, la determinación del
número y tamaño de las particiones, la ubicación de los programas y la protección de las particiones de
memoria.
• Planificación
Un esquema posible para la planificación de procesos a largo plazo, o sea, para seleccionar los procesos
que van cargarse en memoria para ser ejecutados, puede consistir en que cada una de las particiones
tenga una cola asociada, de tal manera que en cada una de ellas se van encolando los trabajos o procesos
dependiendo del espacio de memoria requerido.
Cuando hay que cargar un trabajo, se le pone en la cola de entrada de la partición más pequeña en la
que quepa. Ya que en este esquema las particiones son de tamaño fijo preestablecido, cualquier espacio
de una partición no utilizado por el proceso cargado, se desaprovecha.
La desventaja de meter en colas los trabajos según su tamaño se hace patente cuando la cola de una
partición grande está vacía, pero la cola de una partición pequeña tiene muchos trabajos. Una solución
consiste en tener una única cola. Cuando una partición se queda libre, el primer trabajo de la cola que
quepa en esa partición, se carga en ella y se ejecuta. Ya que no es deseable malgastar una partición
grande con un trabajo pequeño, una alternativa puede ser el recorrer la cola entera y elegir el trabajo
más grande que se pueda cargar en la partición que acaba de quedar libre. No obstante, esto supone una
discriminación de los trabajos con pocos requisitos de memoria, que no son merecedores de tener una
partición grande, mientras que normalmente a los trabajos pequeños se les suele dar el mejor servicio,
no el peor.
Para solucionarlo, se suele disponer siempre de alguna partición de poco tamaño, para permitir que los
pequeños trabajos también se ejecuten sin necesidad de asignarles grandes particiones de memoria. No
obstante, debe tenerse en cuenta que un proceso que requiera poca memoria y mucha CPU puede
entonces formar una larga cola de espera por su partición.

• El tamaño de la partición
El tamaño de cada una de las particiones lo puede establecer el operador en el momento de arranque del
sistema o figurar en algún fichero de configuración del sistema.
Como se puede ver, el grado de multiprogramación está directamente ligado al número de particiones del
sistema. A más particiones, más procesos cargados y, por lo tanto, mayor aprovechamiento de la CPU.
Así, cuanta más memoria se desperdicie, menos procesos se podrán tener en memoria.
Para lograr el mayor aprovechamiento de la memoria los procesos deberían cargarse en particiones cuyo
tamaño se ajuste lo más posible (por exceso) al del proceso. Por una parte tenemos que si dividimos la
memoria del sistema en muchas particiones pequeñas, puede dar lugar a que algunos programas grandes
no puedan cargarse en memoria aunque haya suficiente memoria disponible, si ésta no se encuentra
adyacente en una única partición, dando lugar, en este caso, a una fragmentación externa de la
memoria. Si por el contrario, se dispone de unas pocas particiones grandes, los programas pequeños
desaprovecharán la memoria sobrante de la partición que ocupen, lo que da lugar a una fragmentación
interna.

Los tamaños de las particiones suelen establecerse después de un estudio sobre los tamaños habituales
de los programas que se ejecutan en cada máquina.
• Reubicación de Programas
Cuando se monta o enlaza un programa compuesto por diferentes módulos, todos ellos se combinan en un
único módulo cargable, en el que las referencias a sus objetos locales (rutinas o datos) son direcciones
que van desde cero hasta la correspondiente al tamaño del módulo. Así, si el módulo se carga en la
dirección cero de memoria principal, se ejecutará correctamente, pero no si se carga en cualquier otra
dirección. Según esto, habría que decirle al montador en qué dirección se va a cargar ese programa. Pero
observando cualquiera de los esquemas de la Figura 5, se puede ver que cada proceso se puede cargar en
cualquier dirección de memoria, y no hay forma de conocerla hasta llegar el momento de su ejecución.
Supongamos que la primera instrucción de un programa es una llamada a un procedimiento en la
dirección
100 dentro del fichero binario producido por el montador. Si este programa se carga en la partición 1, esa
instrucción saltará a la dirección absoluta 100, la cual, muy posiblemente, corresponderá a un área del
sistema operativo. Lo que se necesita es que la instrucción salte a la dirección Base_Partición + 100. Así,
siempre se realizará la llamada correcta, independientemente de la partición en la que se cargue el
programa.
Una posible solución consiste en modificar las direcciones del programa a medida que se carga en
memoria. O sea, que a los programas que se carguen en la partición 1 se les añadirá Base_Partición_1 a
todas las direcciones a las que haga referencia, Base_Partición_2 a los que se carguen en la partición 2,
etc.; siendo la base de la partición, su dirección de comienzo. Para realizar esto, el montador debe
incluir en el módulo cargable una lista con las direcciones relativas del programa en las que hay bytes o
palabras cuyo contenido son referencias a
memoria, de tal forma que puedan ser reubicadas en la carga. Con esta solución se
consiguen programas estaticamente reubicables (reubicables en tiempo de carga), pero tienen una pega:

“No permite que un programa cargado en una partición pueda moverse a otra distinta antes de finalizar
su ejecución, lo cual resulta de gran utilidad, como veremos posteriormente.”

Este problema se solventan con un poco de ayuda del hardware, tal como se describe en la parte
superior de la Figura 7. Consiste en equipar al procesador con un nuevo registro: el Registro base.
Cuando un proceso es seleccionado para pasar a ejecución, el registro base se carga con la dirección de
la partición que contiene al proceso en cuestión. Una vez que el proceso está en ejecución, a cada
referencia a memoria se le añade automáticamente el contenido del registro base, generando así la
dirección definitiva, sin necesidad de modificar el contenido del módulo ejecutable, ni en la carga ni
durante la ejecución. A este sistema en el que ya sí se permite ejecutar programas en cualquier partición
de memoria e incluso cambiarlos de partición durante su ejecución, se le conoce como sistema de
Reubicación dinámica.
Solucionado el asunto de la reubicación, debemos afrontar un último problema, pues el sistema de
gestión de memoria que hemos visto hasta ahora no asegura que un programa no pueda construir una
instrucción en la que referencie cualquier dirección de memoria y acceda ilegalmente a datos de áreas
no autorizadas. Esto se resuelve con un “sistema de protección”.
• Protección
El sistema de protección se encarga de evitar el acceso indiscriminado a cualquier área de memoria. A
partir del sistema de reubicación dinámica resulta fácil limitar las referencias a memoria que puedan
hacerse desde un programa.
Para ello añadimos un registro más al procesador: el Registro límite. En la parte inferior de la Figura 7
vemos que para evitar un acceso indiscriminado o por error a cualquier dirección de memoria, lo que se
hace es cargar el registro límite al mismo tiempo que el registro base. El registro límite expresa el
tamaño del programa en ejecución. Cada dirección virtual (relativa) a la que se hace referencia en el
proceso se compara con el valor del registro límite, de tal forma que si tal dirección es menor que el
registro límite, quiere decir que hace referencia a una posición dentro del programa, por lo que
simplemente hay que añadirle el contenido del registro base para obtener la dirección efectiva.
(También puede realizarse la comprobación del registro límite paralelamente a la suma del registro
base). Si por el contrario, la dirección virtual excede al valor del registro límite, indica que se intenta un
acceso a una posición de memoria fuera del área ocupada por el programa, en cuyo caso habrá que
generar la correspondiente excepción de Error de direccionamiento para darle el tratamiento pertinente.
El tamaño que ocupa un proceso suele venir indicado en el módulo cargable, y puede guardarse en el BCP
de cada proceso.
El uso de las particiones fijas es prácticamente nulo hoy día. Como ejemplo de un sistema operativo con
esta gestión de memoria tenemos al antiguo OS/MFT, utilizado por los grandes ordenadores de IBM.

También podría gustarte