Está en la página 1de 6

Gestión de memoria

La memoria una gran matriz de palabras o bytes, cada uno con su propia dirección. La CPU extrae instrucciones de la memoria según
el valor del contador de programa. Estas instrucciones pueden hacer que se carguen valores de direcciones de memoria específicas
o que se guarden en ellas.
Un ciclo de ejecución de una instrucción primero extrae una instrucción de la memoria. Luego, la instrucción se decodifica y se
extraen de memoria una serie de operandos si la instrucción lo necesita. Después de haber ejecutado la instrucción con esos
operandos, se almacenen los resultados en la memoria. La unidad de memoria sólo ve un flujo de direcciones de memoria y no sabe
cómo se generan esas direcciones (mediante el contador de programa, mediante indexación, indirección, direcciones literales, etc.)
ni tampoco para qué se utilizan (instrucciones o datos).

Vinculación de direcciones
Usualmente, los programas residen en un disco como archivos binarios ejecutables. Para poder ejecutarse, un programa deberá ser
cargado en memoria y colocado dentro de un proceso.
Dependiendo del mecanismo de gestión de memoria que se utilice, el proceso puede desplazarse entre disco y memoria durante su
ejecución. Los procesos del disco que estén esperando a ser cargados en memoria para su ejecución forman la cola de entrada.
El procedimiento normal es seleccionar uno de los procesos de la cola de entrada y cargarlo en la memoria. A medida que se ejecuta
el proceso, accede a las instrucciones y datos de la memoria. Cuando el proceso terminará su ejecución, su espacio de memoria
queda disponible.
El programa de usuario debe pasar por varias etapas antes de ejecutarse. En cada etapa, las direcciones se representan de diferentes
formas. Las direcciones del programa fuente son simbólicas. Un compilador vincula las direcciones simbólicas con direcciones
reubicables. El editor de montaje o cargador vincula las direcciones reubicables con direcciones absolutas. Cada vinculación es una
transformación de un espacio de direcciones a otro.
La vinculación de las instrucciones y los datos con direcciones de memoria se pueden hacer en cualquiera de las etapas:
Tiempo de compilación: Si al momento de compilar se sabe en qué parte de la memoria va a residir el proceso, se genera un código
absoluto. Si luego la posición inicial cambia, se deberá recompilar el código.
Tiempo de carga: Si al momento de compilar no se sabe en qué parte de la memoria va a residir el proceso, se genera un código
reubicable. En este caso, la vinculación final se retrasa hasta el momento de la carga. Si la dirección inicial cambia, sólo se volverá a
cargar el código de usuario para incorporar el valor modificado.
Tiempo de ejecución: Si, durante su ejecución, un proceso puede desplazarse de un segmento de memoria a otro, la vinculación se
retarda hasta el momento de la ejecución. Para que este esquema funcione se necesita de hardware especial.

Carga dinámica
Es un mecanismo que se utiliza para obtener una mejor utilización del espacio de memoria. Con esta técnica, una rutina no se carga
hasta que se la invoca; todas las rutinas se mantienen en disco en un formato de carga reubicable. El programa principal se carga en
la memoria y se ejecuta. Cuando una rutina necesita llamar a otra, primero comprueba si la otra ya se cargó. si no es así, se invoca
el cargador de enlace reubicable para que cargue la rutina deseada en memoria y actualice las tablas de direcciones del programa
para reflejar este cambio. Después, se pasa el control a la rutina recién cargada.
VENTAJAS: si una rutina no se utiliza no se carga en memoria. Este método es útil cuando se necesitan grandes cantidades de código
para gestionar casos que sólo ocurren de manera infrecuente, como por ejemplo rutinas de error. Aunque el tamaño total del
programa pueda ser grande, la porción que se utilice (y que por tanto se cargue) puede ser mucho más pequeña.
La carga dinámica no requiere soporte especial por parte del sistema operativo. Los usuarios diseñan sus programas para poder
aprovechar este método.

Montaje dinámico y bibliotecas compartidas


El concepto de montaje binario es similar al de carga dinámica. Lo que se pospone hasta el momento de la ejecución es el montaje,
en lugar de la carga. Esta característica suele usarse con las bibliotecas del sistema, como las bibliotecas de subrutinas del lenguaje.
Si no se cuenta con este recurso, cada programa de un sistema deberá incluir una copia de su biblioteca de lenguaje (o al menos de
las rutinas a las que haga referencia el programa) dentro de la imagen ejecutable. Este requisito hace que se desperdicie tanto
espacio de disco como memoria principal.
Con el montaje dinámico, se incluye un stub (fragmento) dentro de la imagen para cada referencia a una rutina de biblioteca. El
stub es un pequeño fragmento de código que indica cómo localizar la rutina adecuada de biblioteca residente en memoria o cómo
cargar la biblioteca si esa rutina no está todavía presente.
A diferencia de la carga dinámica, el enlace dinámico requiere algo de ayuda del sistema operativo. Si los procesos en memoria están
protegidos unos de otros, entonces el sistema operativo es la única entidad que puede comprobar si la rutina necesaria se encuentra
en el espacio de memoria de otro proceso y puede permitir a múltiples procesos acceder a las mismas direcciones de memoria.
Superposiciones (incompleta)
Es una técnica que permite a los proceso ser mas grandes que la memoria asignada. Lo que se busca es mantener en la memoria
solo las instrucciones y datos que se necesitaran en cualquier momento. Si se necesitan otras instrucciones, se cargan en un espacio
que antes estaba ocupado por otra instrucción que ya no se necesitan.

8.1.3 Espacios de direcciones lógico y físico (incompleto)


Una dirección generada por la CPU se denomina dirección lógica, mientras que una dirección vista por la unidad de memoria (es
decir, la que se carga en el registro de direcciones de memoria de la memoria) se denomina dirección física.
Los esquemas de vinculación de direcciones durante la compilación y durante la carga generan direcciones lógicas y físicas idénticas.
Sin embargo, la ejecución del esquema de vinculación de direcciones durante la ejecución hace que las direcciones lógica y física
difieran. En este caso, la dirección lógica se llama dirección virtual. El conjunto de direcciones lógicas generadas por un programa
se denomina espacio de direcciones lógicas; el conjunto de direcciones físicas correspondientes a estas direcciones lógicas es un
espacio de direcciones físicas. Así, en el esquema de vinculación de direcciones en tiempo de ejecución, los espacios de direcciones
lógicas y físicas difieren.
La transformación de direcciones virtuales a físicas en tiempo de ejecución es producida por la unidad de gestión de memoria
(MMU) un dispositivo de hardware.

Podemos seleccionar entre varios métodos distintos para establecer esta correspondencia, como veremos en las Secciones 8.3 a
8.7. Por el momento, vamos a ilustrar esta operación de asociación mediante un esquema MMU simple, que es una generalización
del esquema de registro base descrita en la Sección 8.1. El registro base se denominará ahora registro de reubicación. El valor
contenido en el registro de reubicación suma a todas las direcciones generadas por un proceso de usuario en el momento de
enviarlas a memoria (véase la Figura 8.4.).

Por ejemplo, si la base se encuentra en la dirección 14000, cualquier intento del usuario de direccionar la posición de memoria cero
se reubicará dinámicamente en la dirección 14000; un acceso a la ubicación 346 se convertirá en la ubicación 14346. El sistema
operativo MS-DOS que se ejecuta sobre la familia de procesadores Intel 80x86 utiliza cuatro registros de reubicación a la hora de
cargar y ejecutar procesos.
El programa de usuario nunca ve las direcciones físicas reales. El programa puede crear un puntero a la ubicación 346, almacenarlo
en memoria, manipularlo y compararlo con otras direcciones, siempre como el número 346. Sólo cuando se lo utiliza como dirección
de memoria (por ejemplo, en una operación de lectura o escritura indirecta) se producirá la reubicación en relación con el registro
base. El programa de usuario maneja direcciones lógicas y el hardware de conversión (mapeo) de memoria convierte esas
direcciones lógicas en direcciones físicas. Esta forma de acoplamiento en tiempo de ejecución ya fue expuesta en la Sección 8.1.2.
La ubicación final de una dirección de memoria referenciada no se determina hasta que se realiza esa referencia.
Ahora tenemos dos tipos diferentes de direcciones: direcciones lógicas (en el rango comprendido entre 0 y max) y direcciones físicas
(en el rango comprendido entre R + 0 y R + max para un valor base igual a R). El usuario sólo genera direcciones lógicas y piensa que
el proceso se ejecuta en las ubicaciones comprendidas entre 0 y max. El programa de usuario suministra direcciones lógicas y estas
direcciones lógicas deben ser convertidas en direcciones físicas antes de utilizarlas.
El concepto de un espacio de direcciones lógicas que se acopla a un espacio de direcciones físicas separado resulta crucial para una
adecuada gestión de la memoria.
8.2 Intercambio
Un proceso debe estar en memoria para ejecutarse. Pero, los procesos pueden intercambiarse temporalmente de la memoria a un
almacenamiento auxiliar, y luego devueltos a la memoria para continuar su ejecución. Por ejemplo, si se utiliza un entorno de
multiprogramación con un algoritmo de planificación de CPU basado en turnos. Cuando termina un cuantum de tiempo, el
administrador de memoria intercambia a disco el proceso que acaba de terminar y a cargar en el espacio de memoria liberado por
otro proceso (Figura 8.5).

Mientras tanto, el planificador de la CPU asigna un cuantum de tiempo a otro proceso que ya esté en la memoria. Cuando un proceso
termina su cuantum, se intercambia con otro proceso.
El administrador de memoria puede intercambiar procesos con la suficiente rapidez como para que siempre haya procesos en
memoria, listos para ejecutarse, cuando el planificador de la CPU desea asignar el procesador a otra tarea. Además, el cuantum
debe ser lo suficientemente grande como para que pueda realizarse una cantidad razonable de cálculos entre una operación de
intercambios y la siguiente.
En los algoritmos de planificación por prioridad se utiliza una variante de esta política de intercambio llamada rodar hacia fuera,
rodar hacia dentro: cuando un proceso de mayor prioridad llega y desea ser servicio, el administrador de memoria puede
intercambiar a disco el proceso de menor prioridad y, cargar y ejecutar el de mayor prioridad. Cuando el proceso de mayor prioridad
termina, el proceso de menor prioridad puede intercambiarse de nuevo a la memoria y continuar su ejecución.
Normalmente, un proceso que se intercambia a disco se volverá a cargar en el mismo espacio de memoria que ocupaba
anteriormente. Esta restricción depende el método de vinculación de las direcciones. La vinculación debe hacerse en tiempo de
ejecución para que el proceso pueda transferirse a una posición de memoria distinta ya que las direcciones se calculan durante la
ejecución; si la vinculación se hace en tiempo de carga, el proceso no puede transferirse.
El intercambio necesita un almacenamiento auxiliar, que debe ser rápido y debe tener el tamaño suficiente para almacenar las
copias de todas las imágenes de memoria para todos los usuarios, y debe proporcionar un acceso directo a estas imágenes de
memoria.
El sistema mantiene una cola de procesos listos que consiste en todos los procesos cuyas imágenes de memoria están en el almacén
auxiliar o en la memoria y que están listos para ejecutarse. Cada vez que el planificador de la CPU decide ejecutar un proceso, llama
al despachador, que comprueba si el siguiente proceso de la cola está en la memoria; Si no es así, y si no hay una región de memoria
libre, el despachador intercambia el proceso deseado por otro proceso que esté actualmente en memoria. A continuación, recarga
los registros y transfiere el control al proceso seleccionado.
Para un uso eficiente de la CPU, es necesario que el tiempo de ejecución de cada proceso sea mayor que el tiempo de intercambio.
La mayor parte del tiempo de intercambio es tiempo de transferencia. El tiempo de transferencia total es directamente proporcional
a la cantidad de memoria intercambiada.
Es útil conocer exactamente cuánta memoria está utilizando un proceso de usuario, y no simplemente cuánta podría estar utilizando.
Así, sólo sería necesario intercambiar lo que estuviera utilizándose realmente, reduciendo así el tiempo de intercambio. Para que
este método sea efectivo, el usuario debe mantener informado al sistema de cualquier cambio que se produzca en las necesidades
de memoria. Así, un proceso con requisitos de memoria dinámicos necesitará ejecutar llamadas al sistema (request memory y
release memory) para informar al sistema operativo de sus cambiantes necesidades de memoria.
El intercambio está restringido también por otros factores: Para intercambiar un proceso, esté debe estar inactivo. En este sentido,
es necesario prestar una atención las operaciones de E/S pendientes. Un proceso puede estar esperando por una operación de E/S
en el momento en que queramos intercambiarlo con el fin de liberar memoria. En ese caso, si la E/S está accediendo a la memoria
de usuario donde residen los búferes de E/S, el proceso no podrá ser intercambiado.

8.3 Asignación de memoria contigua


La memoria principal debe albergar tanto el sistema operativo como los procesos de usuario.
La memoria está dividida en dos particiones: una para el sistema operativo residente y otra para los procesos de usuario. Es posible
colocar el sistema operativo en la zona baja o en la zona alta de la memoria. El principal factor que afecta a esta decisión es la
ubicación del vector de interrupciones. Puesto que dicho vector suele estar en la parte baja de la memoria, se suele colocar el
sistema operativo en dicha zona.
Asignación con una sola partición
Si el sistema operativo reside en memoria baja y los procesos del usuario se ejecuta en memoria alta, se debe proteger el código y
los datos del sistema operativo para que los procesos de usuario no los modifiquen, y se debe proteger los proces

Antes de seguir analizando la cuestión de la asignación de memoria, debemos hablar del tema de la conversión (mapping, mapeo)
de memoria y la protección. Podemos proporcionar estas caracte¬rísticas utilizando un registro de reubicación, como se explica en
la Sección 8.1.3, con un registro límite, como hemos visto en la Sección 8.1.1. El registro de reubicación contiene el valor de la
dirección física más pequeña, mientras que el registro límite contiene el rango de las direcciones lógicas (por ejemplo, reubicación
= 100040 y límite = 74600). Con los registros de reubicación y de límite, cada dirección lógica debe ser inferior al valor contenido en
el registro límite; la MMU con¬vertirá la dirección lógica dinámicamente sumándole el valor contenido en el registro de
reubica¬ción. Esta dirección es la que se envía a la memoria (Figura 8.6).
Cuando el planificador de la CPU selecciona un proceso para su ejecución, el despachador carga en los registros de reubicación y de
límite los valores correctos, como parte del proceso de cambio de contexto. Puesto que todas las direcciones generadas por la CPU
se comparan con estos registros, este mecanismo nos permite proteger tanto al sistema operativo como a los programas

interrupción: error de direccionamiento


Figura 8.6 Soporte hardware para los registros de reubicación y de límite.
8.3 Asignación de memoria contigua
y datos de los otros usuarios de las posibles modificaciones que pudiera realizar este proceso en ejecución.
El esquema basado en registro de reubicación constituye una forma efectiva de permitir que el tamaño del sistema operativo cambie
dinámicamente. Esta flexibilidad resulta deseable en muchas situaciones. Por ejemplo, el sistema operativo contiene código y
espacio de búfer para los controladores de dispositivo; si un controlador de dispositivo (u otro servicio del sistema opera¬tivo) no
se utiliza comúnmente, no conviene mantener el código y los datos correspondientes en la memoria, ya que podríamos utilizar dicho
espacio para otros propósitos. Este tipo de código se denomina en ocasiones código transitorio del sistema operativo, ya que se
carga y descarga según sea necesario. Por tanto, la utilización de este tipo de código modifica el tamaño del sistema ope¬rativo
durante la ejecución del programa.

8.3.2 Asignación de memoria


Uno de los métodos más simples para asignar la memoria consiste en dividirla en varias particiones de tamaño fijo. Cada partición
puede contener exactamente un proceso, y el grado de multiprogramación estará limitado por el número de particiones disponibles.
Cuando una partición está libre, se elige un proceso de la cola de entrada y se carga en esa partición. Cuando el proceso termina, la
partición queda disponible para otro proceso.
El sistema operativo mantiene una tabla que indica qué partes de la memoria están disponibles y cuáles están ocupadas.
Inicialmente, toda la memoria está disponible para los procesos de usuario y se considera como un bloque grande de memoria
disponible llamado hueco. Cuando llega un proceso y necesita memoria, se busca un hueco lo con el tamaño suficiente como para
ese proceso. Si se lo encuentra, sólo se asigna la memoria justa necesaria, y el resto de la memoria queda disponible para satisfacer
futuras solicitudes.
A medida que los procesos entran en el sistema, se colocan en una cola de entrada. El sistema operativo considera las necesidades
de memoria en cada proceso y la cantidad de memoria disponible, para determinar a qué procesos se le asigna la memoria. Cuando
se asigna un espacio a un proceso, se carga en memoria y puede competir por la CPU. Cuando un proceso termina, libera su memoria,
que el sistema operativo podrá rellenar con otro proceso extraído de la cola de entrada.
El sistema operativo puede ordenar la cola de entrada según un algoritmo de planificación, asignándose memoria a los procesos
hasta que no sea posible cumplir las necesidades de memoria del proceso que sigue, es decir, hasta que no quedan bloques de
memoria (o agujero) lo suficientemente grande como para albergar al siguiente proceso. El sistema operativo puede entonces
esperar hasta que se libre un bloque lo suficientemente grande, o puede buscar en la cola de entrada algún otro proceso con el
tamaño suficiente para hacer uso de ese bloque.
Cuando llega un proceso y necesita memoria, el sistema busca en ese conjunto un agujero con el tamaño suficiente como para
albergar el proceso. Si el agujero es demasiado grande, se lo divide en dos partes: una parte se asigna al proceso que acaba de llegar
y la otra se devuelve al conjunto de agujeros. Cuando el proceso termina, libera su bloque de memoria, que volverá al conjunto de
agujeros.
Si el nuevo agujero es adyacente a otros agujeros, se combinan esos agujeros adyacentes para formar uno de mayor tamaño. En
este punto, el sistema determina si hay procesos esperando a que se les asigne memoria y si esta nueva memoria cumple las
demandas de algunos de los procesos en espera.
Este procedimiento es un caso del problema general de asignación dinámica de almacenamiento: que se trata de cómo satisfacer
una solicitud de tamaño n a partir de una lista de agujeros libres. Hay muchas soluciones a este problema, las estrategias más
utilizadas para seleccionar un agujero libre entre el conjunto de agujeros disponible son:
Primer ajuste: Se asigna el primer agujero que sea lo suficientemente grande. La búsqueda puede comenzar al principio del
conjunto de agujeros o en el punto en que terminó la búsqueda anterior. La búsqueda termina cuando se encuentra un agujero lo
suficientemente grande.
Mejor ajuste: Se asigna el agujero más pequeño que tenga el tamaño suficiente. La búsqueda se hace en toda la lista, a menos que
ésta esté ordenada por tamaño. Esta estrategia crea el agujero más pequeño posible.
Peor ajuste: Se asigna el agujero de mayor tamaño. La búsqueda se hace en toda la lista, a menos que ésta esté ordenada por
tamaño. Esta estrategia genera el agujero más grande posible.
8.3.3 Fragmentación
A medida que se cargan procesos en memoria y se eliminan, el espacio de memoria libre se divide en trozos pequeños. La
fragmentación externa surge cuando hay un espacio de memoria total suficiente como para satisfacer una solicitud, pero el espacio
no es contiguo; la memoria está fragmentada en un gran número de pequeños agujeros. Este problema de fragmentación puede
ser grave. En el peor de los casos, podría haber un bloque de memoria libre (o desperdiciada) entre cada dos procesos; si todos
estos fragmentos de memoria estuvieran en un único bloque libre de gran tamaño, se podría ejecutar varios procesos más.
La selección de primer ajuste o el de mejor ajuste puede afectar al grado de fragmentación, porque la estrategia de primer ajuste
es mejor para algunos sistemas, mientras que para otros resulta más adecuada la de mejor ajuste. Otro factor diferenciador es el
extremo de un bloque libre que se asigne.
Dependiendo de la cantidad total de memoria y del tamaño medio de los procesos, la fragmentación externa puede ser un problema
grave o no. El análisis estadístico de la estrategia de primer ajuste revela, por ejemplo, que incluso con algo de optimización, si
tenemos N bloques asignados, se perderán otros 0,5 N bloques debido a la fragmentación. En otras palabras, un tercio de la memoria
puede no ser utilizable. Esta propiedad se conoce con el nombre de regla del 50 por ciento.

La fragmentación de memoria puede ser también interna, además de externa. Considere un esquema de asignación de particiones
múltiples con un agujero de 18464 bvtes. Suponga que el
siguiente proceso solicita 18462 bytes; si asignamos exactamente el bloque solicitado, nos queda¬rá un agujero de 2 bytes. El
espacio de memoria adicional requerido para llevar el control de este agujero será sustancialmente mayor que el propio agujero.

La técnica consiste en descomponer la memoria física en bloques de tamaño fijo y asignar la memoria en unidades basadas en el
tamaño de bloque. Con esta técnica, la memoria asignada a un proceso puede ser ligeramente superior a la memoria solicitada. La
diferencia entre los dos valores será la fragmentación interna, es decir, la memoria que es interna a una partición pero que no está
siendo utilizada.

Una solución al problema de la fragmentación externa es la compactación. El objetivo es mover el contenido de la memoria con el
fin de tener toda la memoria libre junta, para formar un único bloque grande. Sin embargo, la compactación no siempre es posible.
Si la reubicación es estática y se hace en tiempo de ensamblado o de carga, no puede haber compactación; la compactación sólo es
posible si la reubicación es dinámica y se lleva a cabo en tiempo de ejecución. Si las direcciones se reubican dinámicamente, esto
sólo requiere cambiar de lugar el programa y los datos y luego cambiar el registro base para reflejar la nueva dirección base utilizada.
Si la compactación es posible, hay que determinar su costo. El algoritmo de compactación más simple consiste en mover todos los
procesos hacia uno de los extremos de la memoria; de esta forma, todos los agujeros se moverán en la otra dirección, produciendo
un agujero grande de memoria disponible. Sin embargo, este esquema puede ser muy caro de implementar.
Otra posible solución al problema de la fragmentación externa consiste en permitir que el espacio de direcciones lógicas de los
procesos no sea contiguo, lo que hace que podamos asignar memoria física a un proceso con independencia de dónde esté situada
dicha memoria. Hay dos técnicas complementarias que permiten implementar esta solución: la paginación (Sección 8.4) y la
segmentación (Sección 8.6). Asimismo, estas técnicas pueden también combinarse (Sección 8.7).

Paginación
Es otra solución al problema de fragmentación externa que permite que el espacio de direcciones físicas de un proceso no sea
contiguo. La paginación evita el problema de ajustar los trozos de memoria de tamaño variable en el almacenamiento auxiliar;

8.4.1 Método básico


El método básico para implementar la paginación implica dividir la memoria física en bloques de tamaño fijo llamados marcos y en
dividir la memoria lógica en bloques del mismo tamaño llamadas páginas. Cuando hay que ejecutar un proceso, sus páginas se
cargan desde el almacenamiento auxiliar en los marcos de memoria disponibles. El almacenamiento auxiliar se divide en bloques de
tamaño fijo que tienen el mismo tamaño que los marcos de memoria.

Cada dirección generada por la CPU se divide en dos partes: un número de página (p) y un desplazamiento de página (d). El número
de página se utiliza como índice para una tabla de páginas, la cual contiene la dirección base de cada página en memoria física; esta
dirección base se combina con el desplazamiento de página para definir la dirección de memoria física que se envía a la unidad de
memoria.

El tamaño de página (al igual que el tamaño de marco) está definido por el hardware, y suele ser una potencia de 2, variando entre
512 bytes y 16 MB por página, dependiendo de la arquitectura de la computadora. La selección de una potencia de 2 como tamaño
de página facilita la traducción de una dirección lógica a un número de página y desplazamiento de página.
Si el tamaño del espacio de direcciones lógicas es 2" y el tamaño de página es 2" unidades de direccionamiento (bytes o palabras),
entonces los m — n bits de mayor peso de cada dirección lógica designarán el número de página, mientras que los n bits de menor
peso indicarán el desplazamiento de página. Por tanto, la dirección lógica tiene la estructura siguiente:

donde p es un índice de la tabla de páginas y d es el desplazamiento dentro de la página.

El esquema de paginación es una forma de reubicación dinámica. Cada dirección lógica es asignada por el hardware de paginación
a alguna dirección física. La utilización de la paginación es similar al uso de una tabla de registros base (o de reubicación), uno por
cada marco de memoria.
Cuando usamos un esquema de paginación, no tenemos fragmentación externa: todos los marcos libres podrán ser asignados a un
proceso que los necesite. Sin embargo, lo que puede haber es algo de fragmentación interna, ya que los marcos se asignan como
unidades. si los requisitos de memoria de un proceso no coinciden con las fronteras de página, el último marco asignado puede no
estar completamente lleno.

Si el tamaño de los procesos es independiente del tamaño de las páginas, la fragmentación interna podría ser, como promedio, igual
a media página por cada proceso. Por ello, conviene utilizar página pequeñas. Cuando llega un proceso al sistema para ejecutarlo,
se examina su tamaño expresado en páginas. Cada página del proceso necesitará un marco. Por tanto, si el proceso requiere n
páginas, deberá haber disponibles al menos n marcos en memoria. Si los hay, se los asignará al proceso entrante. La primera página
del proceso se carga en uno de los marcos asignados y se incluye el número de marco en la tabla de páginas para este proceso, y así
sucesivamente.

Un aspecto importante de la paginación es diferencia entre la visión de la memoria que tiene el usuario y la memoria física real. El
programa de usuario ve la memoria como un único espacio que sólo contiene ese programa. La diferencia entre la visión de la
memoria que tiene el usuario y la memoria física real se resuelve mediante el hardware de traducción de direcciones. Las direcciones
lógicas se traducen a direcciones físicas y esta conversión es hecha por el sistema operativo.
Como el sistema operativo gestiona la memoria física, debe ser consciente de los detalles de la asignación de la memoria física: qué
marcos han sido asignados, qué marcos están disponibles, cuál es el número total de marcos, etc. Esta información se guarda en
una estructura de datos llamada tabla de marcos, cual tiene una entrada por cada marco físico que indica si está libre o asignado y,
en caso de estar asignado, a qué página de qué proceso o procesos ha sido asignado.
Además, el sistema operativo debe ser consciente de que los procesos de usuario operan en el espacio de usuario y de que todas
las direcciones lógicas deben ser convertidas con el fin de generar direcciones físicas.

8.4.3 Protección
La protección de la memoria en un entorno paginado se hace mediante bits de protección asociados a cada marco. Estos bits se
mantienen en la tabla de páginas. Un bit define si una página es de lectura-escritura o de sólo lectura. Cada referencia a memoria
pasa a través de la tabla de páginas para encontrar el número de marco correcto. Mientras se calcula la dirección física, se examinan
los bits de protección para verificar que no se esté haciendo ninguna escritura en una página de sólo lectura. Si esto sucede
provocará una interrupción hardware al sistema operativo (o una violación de protección de memoria).
Esta estrategia de protección se puede ampliar fácilmente para proporcionar un nivel más fino de protección. Se Puede crear un
hardware que proporcione protección de sólo lectura, de lectura-escritura o de sólo ejecución. También, se puede permitir cualquier
combinación de estos accesos, si se incluyen bits de protección individuales para cada tipo de acceso. Los intentos no validos
causaran una interrupción de hardware hacia el sistema operativo.
Generalmente, se añade un bit más a cada entrada de la tabla de páginas: un válido-inválido. Cuando este bit indica "válido", la
página asociada se encontrará el espacio de direcciones lógicas del proceso y será una página válida. Cuando este bit indica
"inválido", la página no se encuentra en el espacio de direcciones lógicas del proceso. Las direcciones inválidas se capturan utilizando
el bit válido-inválido. El sistema operativo configura este bit para cada página, con el fin de permitir o prohibir el acceso a dicha
página.

También podría gustarte