Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Cap4 1
Cap4 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.
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.
• 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.