Sistemas Operativos
Sistemas Operativos
Sistemas Operativos
Administración Basica:
Este es un exemplo de las direntes formas en las que se puede dar la
monoprogramacíon, en donde se mantiene la constante de que solo hay un
proceso en memoria, que se comparte únicamente con el Sistema Operativo, que
puede estar en ROM o RAM.
Puede haber diversidad de trabajos por partición, o bien una sola cola general. En
el primer caso, cuando llega un trabajo, se pone en la cola de la partición más
pequeña en la que todavía quepa el trabajo. Si llegan muchos trabajos pequeños
podría pasar que, mientras las colas para las particiones chicas están llenas, las
particiones grandes quedan sin uso. En el caso de una sola cola, cada vez que un
programa termina y se libera una partición, se escoge un trabajo de la cola
general.
Tiempo de compilación.
Cuando al compilar se conoce la dirección absoluta, el compilador escribe la
imagen exacta del código que se cargará en la memoria.
En este caso el código debe cargarse a partir de la dirección 100. Los programas
.COM de MS-DOS son de este estilo.
Tiempo de carga.
Si al compilar no se conocen todavía las direcciones absolutas, hay que generar
código reubicable. El cargador o loader, es responsable de determinar las
direcciones absolutas al momento de poner el programa en memoria. Para eso, el
compilador genera código como para ejecutar a partir de la dirección 0, y agrega
un encabezado con información acerca de cuáles de las posiciones corresponden
a direcciones que deben ajustarse según donde se cargue el programa (¿.EXE de
MS-DOS?).
Tiempo de ejecución.
Si el sistema operativo usa swapping (pasar procesos a disco para hacer espacio
en la memoria), puede que un proceso sea cambiado de posición durante su
ejecución. En este caso se usa hardware especial.
Pero además de la reubicación tenemos el problema de la protección: queremos
que un programa ejecutando en una partición no pueda leer ni escribir la memoria
que corresponde a otra partición. Podemos entonces matar dos pájaros de un tiro
con una variante de los registro base y límite que vimos en el capítulo 1. Cuando
se carga un programa en una partición, se hace apuntar base al comienzo de la
partición, y límite se fija como la longitud de la partición. Cada vez que la CPU
quiere accesar la dirección d, el hardware se encarga de que en realidad se
accese la dirección física base+d (y, por supuesto, además se chequea que
d<límite).
Intercambio o reubicación(swapping)
Por swapping un proceso puede ser reubicado varias veces en memoria principal
Los programadores no saben efectivamente en que lugar de la memoria serán
ejecutados sus programas. Las referencias a memoria tanto en código como en
Datos deben ser traducidas a las direcciones físicas en la que se encuentra el
programa
El sistema operativo mantiene una tabla que indica qué partes de la memoria
están desocupadas, y cuáles en uso. Podemos pensar en que las partes
desocupadas son hoyos en la memoria; inicialmente, toda la memoria es un solo
gran hoyo Cuando se crea un proceso o se trae uno del disco, se busca un hoyo
capaz de contenerlo, y se pone el proceso allí.
Hasta ahora hemos supuesto que los procesos son estáticos en tamaño, pero es
más realista pensar que pueden crecer, por ejemplo vía asignación dinámica de
memoria. Si es así, conviene reservar un poco más de memoria que la que
estrictamente necesita al momento de ponerlo en memoria. Al hacer swapping, no
es necesario guardar todo el espacio que tiene reservado, sino sólo el que está
usando. ¿Qué pasa si proceso quiere crecer más allá del espacio que se le había
reservado? Si hay un hoyo contiguo se puede usar. Si no, se puede pasar el
proceso a un hoyo más grande. Si no hay ninguno, se pasa a disco hasta que
haya. También se puede, simplemente, matar al proceso.
Otro punto que hay que tener en cuenta al usar swappping, es el I/O que pudiera
estar pendiente. Cuando se hace, por ejemplo, input, se especifica una dirección
de memoria donde se va a poner lo que se lea desde el dispositivo. Supongamos
que proceso A trata de leer del disco hacia la dirección d, pero el dispositivo está
ocupado: su solicitud, por lo tanto, es encolada. Entretanto, el proceso A es
intercambiado a disco, y la operación se completa cuando A no está en memoria.
En esas circunstancias, lo leído se escribe en la dirección d, que ahora
corresponde a otro proceso. Para evitar tal desastre: no pasar a disco procesos
con I/O pendiente, o bien hacer siempre I/O desde y hacia buffers del sistema
operativo.
Windows 3.x usa swapping, pero un proceso pasado a disco sólo vuelve a la
memoria si el usuario activa su ventana. Windows NT usa un esquema más
sofisticado. Unix comienza a usar swapping cuando se supera un cierto límite de
utilización de memoria.
Administración de la memoria con lista ligada: Otra forma es con una lista ligada
de segmentos: estado (ocupado o en uso), dirección (de inicio), tamaño. Cuando
un proceso termina o se pasa a disco, si quedan dos hoyos juntos, se funden en
un solo segmento. Si la lista se mantiene ordenada por dirección, podemos usar
uno de los siguientes algoritmos para escoger un hoyo donde poner un nuevo
proceso (cuyo tamaño, obviamente, debe conocerse).
• First-fit. Asignar el primer hoyo que sea suficientemente grande como para
contener al proceso.
Cada vez que se asigna un hoyo a un proceso, a menos que quepa exactamente,
se convierte en un segmento asignado y un hoyo más pequeño. Best-fit deja el
hoyo más pequeño de todos. La idea de worst-fit es la de dejar hoyos grandes.
Simulaciones han mostrado que first-fit y best-fit son mejores en términos de
utilización de la memoria. First-fit es más rápido (no hay que revisar toda la lista).
Se puede pensar en otras variantes (por ejemplo, mantener la lista ordenada por
tamaño, o varias listas, cada una con un rango de tamaños, etc).
Paginación:
Hace tiempo que alguien se dio cuenta de que esto de que los procesos tengan
que usar un espacio contiguo de la memoria era un impedimento serio para poder
optimizar el aprovechamiento de la memoria. Idea: que las direcciones lógicas
sean contiguas, pero que no necesariamente correspondan a direcciones físicas
contiguas. O sea, dividir la memoria física en bloques de tamaño fijo, llamados
marcos o frames, y dividir la memoria lógica (la que los procesos ven) en bloques
del mismo tamaño llamados páginas.
Se usa una tabla de páginas para saber en que marco se encuentra cada página.
Obviamente, necesitamos el apoyo del hardware. Cada vez que la CPU intenta
accesar una dirección, la dirección se divide en número de página p y
desplazamiento u offset d. El número de página se transforma en el frame
correspondiente, antes de accesar físicamente la memoria.
El tamaño de las páginas es una potencia de 2, típicamente entre 0.5 y 8K. Si las
direcciones son de m bits y el tamaño de página es 2n, entonces los primeros m-n
bits de cada dirección forman p, y los restantes n forman d. Este esquema es
parecido a tener varios pares de registros base y límite, uno para cada marco (o
sea, por cierto, tenemos binding en tiempo de ejecución).
Cada proceso tiene su propia tabla, es decir, la tabla de páginas forma parte del
contexto: cuando la CPU se concede a otro proceso, hay que cambiar la tabla de
páginas a la del nuevo proceso. La paginación en general encarece los cambios
de contexto. La seguridad sale gratis, ya que cada proceso sólo puede accesar las
páginas que están en su tabla de páginas.
La gracia es que, por pequeño que sea el TLB, la probabilidad de que la página
esté en el TLB (tasa de aciertos) es alta, debido a que los programas suelen hacer
muchas referencias a unas pocas páginas (por ejemplo, copiar un arreglo). Si la
tasa de aciertos es del 90% y un acceso al TLB cuesta 10ns, entonces, en
promedio, cada acceso a memoria costará 87ns (¿por qué?). o sea, sólo un 24%
más que un acceso sin paginación. Una Intel 80486 tiene 32 entradas en el TLB;
Intel asegura una tasa de aciertos del 98%.
En cada cambio de contexto, hay que limpiar el TLB, lo que puede ser barato, pero
hay que considerar un costo indirecto: si los cambios de contexto son muy
frecuentes, la tasa de aciertos se puede reducir (¿por qué?).
Otras ventaja de paginación: también se facilita almacenamiento de procesos en el
disco; permite que procesos compartan páginas. Por ejemplo, varios procesos
ejecutando el mismo código (que tiene que ser reentrante): las primeras páginas
lógicas apuntan a las mismas páginas físicas, que contienen el código. El resto,
apunta a datos locales, propios de cada ejecución.
Ventajas:
Pero la memoria sigue siendo, físicamente, un sólo arreglo de bytes, que debe
contener los segmentos de todos los procesos. A medida que se van creando y
eliminando procesos, se va a ir produciendo, inevitablemente fragmentación
externa.