Capítulo 6. (FINAL)
Gestión del recurso CPU
Link al cuaderno completo con este tema:
https://notebooklm.google.com/notebook/5e0c387a-9cc6-446f-97e5-fe3f3a36a4bb
Como ya sabemos, la CPU es la parte principal de la computadora a nivel de la arquitectura. En ella ocurre el procesamiento, es decir, la ejecución de cada una de las instrucciones del programa en ejecución.
El nivel de SO agrega la funcionalidad de la multitarea. Entonces se debe crear la ilusión de la ejecución concurrente (en última instancia el SO está simulando la ejecución simultánea a partir de ejecución repetida de diferentes partes).
Esta ilusión de la multitarea es parte del trabajo del núcleo del SO. Concretamente a través del llamado gestor de procesos, o scheduller de procesos.
Vamos a considerar en forma global la administración del recurso CPU por parte del SO.
Vale recordar que no se trata de un RSR, sino todo lo contrario: la CPU es el recurso más arrebatado del sistema, es decir, constantemente el scheduller está quitando la CPU a algún proceso para darla a otro. Es el recurso más apropiable del sistema!
La base de por qué podemos quitar la CPU a un proceso y darla a otro, nos la da el ya estudiado “guardar el contexto”: antes de quitarle la CPU a un proceso, guardamos en su PCB copias de todos los registros; e inmediatamente antes de restituirle la CPU, traemos dichos valores del PCB a los registros. Ya fue estudiado.
Otra parte ya analizada en detalle y que aquí juega un rol central, es la máquina de estados que modela el comportamiento de los procesos en un SO multitarea. Teníamos los estados en ejecución, listo, bloqueado,… más los estados de suspensión.
Ahora, nuestro análisis global de la gestión de CPU nos lleva a plantear 3 niveles de schedulling:
- Nivel alto: Se le llama admisión. Este nivel decide cuáles de las solicitudes de ejecución de trabajos se transformarán en procesos. Un trabajo es un programa que se pretende ejecutar. Si el SO lo permite, tras la petición de ejecución, lo cargará en memoria, lo asignará en el marco de un proceso, y lo ejecutará. Recién en ese momento el trabajo se transforma en proceso.
- En los sistemas operativos, este nivel es absolutamente abierto. Se pueden crear tantos nuevos procesos como se quiera. El SO tratará de ejecutar todo.
- En los sistemas de tiempo real, este nivel es absolutamente cerrado. No hay forma de ejecutar nuevos programas que no esté prevista de antemano. Por ejemplo, la computadora que regula la inyección de combustible en el motor de un auto, no ofrece una interfaz para ejecutar un proceso nuevo.
- Nivel medio: Aquí transcurre la suspensión/reanudación de procesos. Un proceso puede ser suspendido por cualquier razón, siempre de parte del SO: falla de hardware, llegada de proceso urgente, alta carga del sistema, etc. El nivel de suspensión/reanudación sobre procesos que YA SON parte de la ejecución del sistema, es este nivel medio.
- En los sistemas operativos juega un rol bastante nominal, o sea hace poco, pues al tratar todos los procesos de igual forma, no hay tantas chances de suspensión.
- En los sistemas de tiempo real, y también en los SOTR (como por ejemplo Android), este nivel juega un rol más activo en lo que a suspensión de procesos se refiere.
- Nivel bajo: Es el schedulling en sí mismo, llamado también despachador de procesos.
- Lo vamos a estudiar en detalle ahora. Determina a quién le toca la CPU en un momento dado.
El despachador o scheduller debe residir en memoria principal en todo momento. Es la parte principal del sistema operativo. Su función es determinar cuál será el próximo proceso listo a ejecutar.
Por qué listo ? Recordemos que los procesos bloqueados no forman parte de los candidatos a recibir CPU pues están esperando la ocurrencia de determinado evento, comúnmente la disponibilidad de algún recurso.

Vamos a analizar la ejecución de procesos a bajo nivel, el scheduller. Para ello tomaremos una lista de asuntos a considerar:
- Objetivos
- Elementos con los cuales decir el schedulling
- Las políticas concretas
Objetivos de las políticas de schedulling:
Los objetivos, en este caso, actúan como una lista de deseos, es decir, no será sencillo satisfacer todos a la vez, porque algunos se contraponen…
Aquí aparece el concepto de TRADE OFF. Es decir, maximizar o minimizar alguna medida de calidad, pero sin dejar de ceñirse a determinadas restricciones.
Aquí tendremos dos medidas de calidad:
- Si se trata de un Sistema Operativo se busca MAXIMIZAR EL RENDIMIENTO DEL SISTEMA, EL USO DE LOS RECURSOS, EL CÓMPUTO.
- Si se trata de un Sistema de Tiempo Real, se busca MINIMIZAR LOS TIEMPOS DE RESPUESTA.
Estos son dos escenarios completamente diferentes y que por lo tanto van a determinar la arquitectura del scheduller.
Aparecen otros objetivos a considerar, sin dejar de tener en cuenta los anteriores, fundamentales.
Otros objetivos para una política de schedulling:
- Ser justa, en cuanto a no favorecer arbitrariamente y por tanto no generar aplazamiento indefinido.
- Manejar prioridades (como vemos, es contraria a la anterior). En función de las necesidades en las que se inserta el sistema, decidir (trade off) qué procesos y en qué medida priorizar.
- Ser predecible: ejecutar las tareas en forma independiente de la carga del sistema. Sabemos que esto, escrito literalmente, es irreal, un sistema cargado ejecuta más lento. Sin embargo se trata de buscar, dentro de parámetros razonables de carga, un funcionamiento regular del sistema, con tiempos de respuesta acotados, contenidos. Sabemos que de un nivel de carga en adelante, el sistema dispara sus tiempos, y se torna más difícil el trabajar con él.
- Minimizar el gasto extra, es decir el overhead. No olvidemos que la ejecución del scheduller es todo overhead, no es cómputo. Por tanto, todo este código debe ser simple, ágil, liviano, de modo de no interferir con el cómputo en sí mismo, no restar capacidad de cómputo.
- Maximizar el paralelismo intrínseco a la arquitectura. O sea, favorecer la utilización simultánea de los dispositivos que así lo permitan. Por ejemplo una impresora (que tiene su propia CPU y memoria) y un scanner (que tiene su propia CPU y memoria).
- Equilibrar aprovechamiento con tiempo de respuesta. Aquí hay que tomar decisiones de trade off pues tiempos de respuesta bajos requieren recursos ociosos.
- Favorecer recursos decisivos. Esto es muy de difícil de determinar… En un STR podría estar más claro.
- Favorecer procesos que vienen estables. Esto es muy difícil de determinar… En un STR podría estar más claro por ser pocos procesos y siempre los mismos.
- Absorber y degradar en forma gradual los picos de carga. No colapsar por una llegada puntual de procesos, requerimiento de memoria, transacciones, etc. sino que atender todo dentro de la medida, sacrificando lo menos posible los parámetros de calidad y sin dejar de ejecutar los procesos de fondo, aunque sin ignorar los procesos derivados/causantes de la gran carga.
Esta lista nos muestra la complejidad detrás de este tema, en apariencia tan simple.
Criterios y elementos para construir las políticas de planificación
- Limitación de procesos por Entrada Salida: decimos que un proceso está limitado por E/S cuando hubiera perdido la CPU pasando al estado bloqueado, es decir, probablemente, por esperar por la disponibilidad de un RSR.
- Estos procesos son los más convenientes para el sistema, en su globalidad, pues no requieren intensivamente de CPU. Y además, con la multitarea simulada, el sistema gana mucho en performance, pues estos procesos generan esperas por los recursos.
- Cuando un proceso bloqueado finalmente recibe el recurso o evento por el cual esperaba, vuelve a la lista de listos y espera por la CPU, según la política de schedulling.
- Limitación de un proceso por CPU: decimos que un proceso está limitado por CPU cuando hubiera perdido la CPU pasando al estado listo, es decir, por expiración de su quantum de tiempo.
- Son peligrosos, pueden ser acaparadores de CPU. Ralentizan el sistema.
- Cuando el proceso agota su quantum de tiempo, va a la lista de listos, en algún orden, según la política de schedulling, y espera para ejecutar de nuevo (ver máquina de estados).
- El quantum de tiempo puede ser fijo o variable, normalmente alcanza para ejecutar miles de instrucciones…
- Si un proceso es por lotes, va a conformarse con algunos mecanismos muy estáticos de schedulling ya que no precisa estar cambiando la CPU entre procesos.
- Por el contrario los procesos interactivos requerirán que la CPU pase de unos a otros en forma constante.
- El grado de urgencia de la respuesta obviamente determina el schedulling también. En los STR puede ser alto.
- Otros insumos para la decisión del schedulling:
- Alojamiento / desalojamiento de memoria. Un proceso que es frecuentemente desalojado de memoria no tiene la importancia de un proceso core.
- Frecuencia con que un proceso debe liberar y entregar recursos en forma forzada.
- Tiempo real de ejecución recibido por un proceso.
- Y cuánto tiempo le falta para terminar … PODEMOS DETERMINARLO ? No podemos determinarlo (basta con que entre en loop…) PERO producto de algunas salvajes simplificaciones podemos llegar a estimarlo (y muy malas estimaciones). Por ejemplo podríamos estimar por datos históricos.
- Planificación no apropiativa: en ella, al recibir un proceso la CPU, ya no la devuelve hasta finalizar, ejecuta hasta finalizar. Funciona tipo fila en la caja del supermercado, cuando le comienzan a cobrar a alguien, ya no se abandona el cobro hasta finalizar.
- Los trabajos largos perjudican a los trabajos cortos.
- Formalmente justa.
- No apta para STR ni para sistemas interactivos.
- Perfecta para sistemas batch.
- Se lleva muy mal con las prioridades pues una vez que asignó la CPU no puede desasignarla.
- Planificación apropiativa: en ella la CPU puede ser arrebatada, por el SO, o por otro proceso. Esto permitirá llevar el multitasking con tiempos de espera razonables.
- Este tipo de planificación favorece la computación de tiempo real y la atención simultánea a usuarios interactivos. De otro modo tendríamos demoras descontroladas.
- La apropiación tiene un precio en overhead, que es el cambio de contexto.
- La planificación apropiativa, debe lidiar, entre otras cosas, con la determinación de tiempos. Cómo sabemos que transcurrió el quantum de tiempo ?
- Lo sabemos porque tenemos el reloj de interrupciones.
- La cpu oscila en una frecuencia conocida, y su inversa, el período, nos da la base de tiempos del sistema. Basta contar tics de ocurrencia de intervalos definidos, y en función de los mismos determinar cuánto tiempo ha trascurrido. En base a esto medimos si pasó el quantum de tiempo completo o no.
- En base a estas interrupciones que ocurren en intervalos de tiempo preestablecidos y conocidos, podemos determinar tiempos transcurridos, y así tomar decisiones en función de los mismos.
- Entonces podemos agendar procesos, determinar tiempos transcurridos y tomar cualquier decisión en base a estos tiempos.
- Prioridades de los procesos:
- Puede haber varios esquemas: estáticos vs dinámicos. Prioridades fijas vs variables a lo largo del tiempo.
- Pueden asignarse externamente o de acuerdo a alguna dinámica de comportamiento del sistema, etc.
Políticas de planificación

Planificación de plazo fijo
Esta política muchas veces aparece ASOCIADA a alguna otra, por ej Round Robin.
Implica que algunas tareas reciben parámetros de obligatoriedad de terminación absolutos o relativos. Ej absolutos: terminar la tarea X antes de las 03.00. Ej relativos: tenemos 5 segundos para cerrar la puerta.
Algunas tareas quedan etiquetadas con tiempos establecidos.
Se debe ejecutar lo que se estuviera ejecutando y necesitara ejecutar sin descuidar estas tareas con tiempos de terminación obligatorios.
Por otra parte tal vez esos tiempos sean demasiado exigentes, o imposibles en gral, o imposibles en determinado contexto.
Puede que cada tarea de plazo fijo, individualmente sea factible, pero que la mezcla sea inimplementable.
La admisión de tareas de plazo fijo puede implicar decisiones que el sistema no esté en condiciones de evaluar objetivamente y por tanto la factibilidad de su exitosa ejecución quedaría librada a la suerte.
TIENEN SENTIDO SI en los STR. Por ejemplo, abrir los airbags antes de xx ms luego de detectado el choque. En este caso todo el sistema está diseñado en torno a dicha restricción.
En la generalidad de un SO es muy difícil que aporten algo.
Primero en Entrar Primero en Salir PEPS o FIFO
No es apropiativa.
Se hace una fila para el uso de la CPU.
El que toma la CPU ejecuta hasta finalizar.
Los trabajos largos retrasan a todo el mundo, incluidos los trabajos rápidos de alta prioridad.
Cuando un proceso toma la CPU, ejecuta hasta finalizar.
Formalmente justa.
Perfecta para los trabajos BATCH.
No apta para STR ni para sistemas de tiempo compartido.
Altamente predecible.
Rara vez usada actualmente.
ROUND ROBIN o PEPS apropiativa o FIFO apropiativa o por turno.
Es la contraparte apropiativa de PEPS.
Los procesos se organizan en fila.
Un proceso ejecuta hasta que o bien hace una E/S y pasa al estado bloqueado o bien expira su quantum de tiempo, y pasa al estado listo.
Simple. ágil. Justa. NO genera aplazamiento indefinido.
Requiere de una organización en cola.
Apta para tiempo compartido.
Apta para STR con cuidado. Tal vez complementando con algún esquema de prioridades.
Poco overhead en el pasaje de un proceso a otro. Es decir en la apropiación. Y la carga de los procesos a memoria es la obvia: cargamos a memoria todo proceso participante del RR.
El quantum puede ser fijo o variable.
En general es de tamaño fijo.
Un quantum muy grande, infinito, degenera en PEPS.
Un quantum muy pequeño, nos hace constantemente cambiar de una tarea a otra y por tanto de contexto.
Entre ambos existe un tamaño óptimo para el quantum, que normalmente lo fija el fabricante, dando una aproximación lo mejor posible.
Al haber una fila, no hay aplazamiento indefinido.
SJF SHORTEST JOB FIRST
Se ordena la fila con los trabajos más cortos al comienzo.
Es no apropiativa y similar a PEPS.
Creo la falsa ilusión de que voy más rápido. En realidad estoy haciendo los trabajos más cortos primero…
Hay aplazamiento indefinido para los trabajos largos, ya que el sistema los deja para cuando no tiene nada mejor que hacer.
Si hacemos un estudio matemático de los tiempos de respuesta, nos da que el tiempo de respuesta mejora.
SRT SHORTEST REMAINING TIME
Es SJF pero apropiativa.
Por tanto cada vez que hay una E/S se pasa a otro proceso. Siempre tomando el que le queda menos para terminar.
SRT y SJF se basan en que podemos estimar correctamente los tiempos de ejecución, lo cual es falso. No sabemos cuánto lleva ejecutar una tarea!
Hay otras políticas de planificación, basadas en el tiempo restante, tiempo real de ejecución, etc.
Nos queda ver las COLAS DE RETROALIMENTACION MULTINIVEL como política adaptativa de schedulling.
Retomamos las estrategias schedulling con las colas de retroalimentación de múltiples niveles.
Esta estrategia es adaptatativa, es decir, reacciona, en runtime, a los diferentes tipos de procesos que maneja.
Trata de sensibilizar, determinar cuanto antes, si un proceso es interactivo o si básicamente consume mucha CPU.
Expliquémoslo para 3 niveles.
Se manejan 3 colas de ejecución, de niveles 1, 2 y 3
Todos los procesos arrancan haciendo fila en la cola 1, la cual se maneja por Round Robin RR.
Mientras van perdiendo el procesador, se evalúa:
Si lo perdieron por E/S, se continúa en el nivel 1 y se pone el proceso al final de la cola del nivel 1.
Si por el contrario pierde el procesador por TIMEOUT, corta por CPU, entonces se lo coloca al final de la cola 2.
La cola 2 es de menor prioridad que la cola 1. Por ejemplo cada 10 ciclos en la cola 1, ejecuto uno en la cola 2.
Si los procesos de la cola 2 cortan por CPU, los bajo a la cola 3. Si en cambio cortan por E/S, los pongo al final de la cola 1.
La cola 3 es de menor prioridad que la cola 2. Por ejemplo cada 100 ciclos de la cola 1, ejecuto 1 de la cola 3.

En la cola 1 van quedando los procesos interactivos, que hacen E/S. Se supone que requieren respuestas rápidas y este método los atiende primero.
Además son procesos que no castigan la eficiencia del sistema. Porque ejecutan un poquito y enseguida se van a esperar una E/S.
En la cola 3 se van depositando los procesos que cortan por CPU. Grandes consumidores de CPU y que perjudican la performance global del sistema. Se los ejecuta apenas en los ratos libres o con menor frecuencia que los demás.
Entonces este mecanismo es adaptativo pues responde a cambios en las necesidades de uso de CPU y se va adaptando con los procesos.
La cola 2 es de tránsito intermedio hacia la cola 3. Capaz algún proceso que cortó por CPU pero enseguida vuelve a cortar por E/S, vuelve más rápido a la fila 1 que si hubiera descendido por todo los niveles.
Este mecanismo tiene más overhead en tiempo y en espacio.
Este mecanismo es sensible a la forma en que los procesos consumen CPU.
Este mecanismo da prioridad a los procesos que realizan entrada salida.
Este mecanismo aparta a los grandes consumidores de CPU, ejecutándolos con más baja frecuencia. Los ejecuta cuándo no tiene nada más prioritario que hacer.
DISCUSION: Diferencia entre PEPS y RR ? RR es apropiativo. Podemos quitarle la CPU a un proceso. PEPS no. PEPS incluso espera por E/S. Sólo sirve para batch. En cambio RR permite compartir recursos y compartir la CPU, sirve para sistemas interactivos e incluso para algún STR, con las modificaciones del caso.
Ejercicio
Proponer políticas de schedulling de nivel alto, medio y bajo, y justificar, para los siguientes casos:
- Un sistema operativo genérico para PC. Ej. Windows, Linux.
A nivel alto, abierto. SO genérico. Acepta nuevas tareas en cualquier contexto. No podemos a priori definir escenarios donde favorecer / desfavorecer / no permitir ejecutar /cerrar procesos.
A nivel medio, sin énfasis, INACTIVO (la suspensión/reanudación). Ya que se trata de un SO genérico.
A nivel bajo, usamos Round Robin. Es apropiativo y es simple. Permite la multitarea. Permite el trabajo en base a tiempo compartido.
- Un sistema operativo para una Tablet tipo Ipad, sin llamadas.
Es totalmente equivalente al caso anterior, donde no hay ningún aspecto de temporalidad a contemplar.
A nivel alto, abierto.
A nivel medio, no aparecen procesos que priorizar así que inactivo, sin énfasis, etc.
A nivel bajo, RR.
En los escenarios genéricos no podemos establecer prioridades, porque no sabemos qué es lo que vendrá.
- Un sistema operativo para un celular SMARTPHONE. Ej Android.
Tenemos características de SO por el multitasking, pero también características de temporalidad fuerte por ser STR.
A nivel alto: abierto.
A nivel medio: activo. Necesitamos poder suspender tareas, procesos, debido a la llegada de eventos como las llamadas.
La llamada de Whatsapp es suspendida por la llamada común! Porque Whatsapp es para el teléfono una aplicación menos prioritaria que la llamada de línea.
A nivel bajo: RR con prioridades. Es genérico pero soporta la temporalidad de la llamada.
- Un sistema operativo para un STR tipo un aire acondicionado.
Se trata de un STR aunque no de eventos vitales. Podríamos decir que un STR soft.
A nivel alto: cerrado.
A nivel medio: no hay nada grave que amerite suspensión… sin énfasis.
A nivel bajo: RR eventualmente con prioridad. También, siendo TAN POCOS PROCESOS y TAN POCOS RECURSOS, podríamos recurrir a un schedulling a la medida. Esto es definimos un orden y quantums de tiempo individuales y vamos cambiando entre procesos en ese orden y con esos quantums.
SI tenemos que hacer un STR que tiene 3 procesos A, B y C, y necesito que se ejecute A el doble de tiempo que B y que C, capaz que la mejor forma es definir una ronda de schedulling así:
ABACABAC…etc
Y lo hago “a pedal” y no complicamos las cosas, ya que son sólo 3 procesos…
También podríamos jugar con el quantum variable y hacer:
ABCABCABC… pero con el qA=2qB=2qC
Supongamos que queremos detectar sobreconsumo, y no lo dejamos encendido más de N minutos. Ahí más que suspensión, podríamos tener otro proceso monitor, que tiene la potestad de un apagado…
Con la suspensión resolvemos desde afuera, cuando es más tipo caso de uso, lo que hacemos es considerarlo dentro de los procesos.
- Un sistema operativo para dar soporte a tiempo real del estilo de RTLinux. Es un SOTR. Es más agresivo que Android respecto a las prioridades.
Maneja dos niveles de prioridad y SOLO si le sobra el tiempo ejecuta nivel bajo.
RTLinux es un Linux en el cual algunos procesos están claramente priorizados respecto al resto.
A alto nivel: cerrado. Por ser STR.
A nivel medio: activo por si hay algunas tareas de altísima prioridad.
A nivel bajo: RR con pioridades. También podría ser colas de retroalimentación en 2 niveles. Sin embargo tiene tal vez demasiado overhead.
No consideramos un schedulling a la medida porque en este caso propone un comportamiento genérico. No sé cuántos procesos hay!
- Un STR que gestione en base a un arduino, un conjunto de sensores y actuadores.
A nivel alto: cerrado por ser STR.
A nivel medio: activo por ser STR. Tal vez podríamos ignorar este nivel y manejarlo a bajo nivel, dada la escasa complejidad del aparato.
A bajo nivel: podríamos usar RR con prioridades. Pero siendo unos pocos sensores y unos pocos actuadores, entonces, es probable que convenga más un scheduller a la medida.
Cómo se hace la multitarea en el Arduino ? Mucha gente dice que el Arduino es monotarea y que si quiero multitarea debo usar una Raspberry, que tiene el núcleo de Linux…
Así que en estos casos puede ser más conveniente decir que hacemos un scheduller a la medida.
- Un sistema batch.
Es un sistema que ejecuta en forma lineal, un conjunto de tareas una detrás de la otra. No interactivas. Ni siquiera aprovecha el tiempo ocioso de CPU entre operaciones de entrada salida.
Ejecuta una sola lista de tareas y nada más y en esa lista, estrictamente de a una por vez.
Alto nivel: Cerrado
Nivel medio: inactivo
Bajo nivel: PEPS. Es no apropiativo, y en el batch una vez que tengo la CPU no tengo que devolverla. El que ejecuta lo hace hasta el final.
Ya no se usa el batch…
- Un sistema para controlar los airbags de un auto.
Un STR con temporalidad fuerte.
Alto nivel: CERRADO. Ni siquiera una interfaz para generar tareas.
Nivel medio: ACTIVO. Responder a tiempo es lo único que importa.
Bajo nivel: RR con prioridades o si fuera muy sencillo, un schedulling a la medida.
Qué procesos tendría ?
Es un sistema de tiempo real con una temporalidad muy agresiva.
Tiene que vigilar un conjunto de sensores y actuar sobre los detonadores de los airbags, pretensores pirotécnicos de los cinturones, cortar el combustible, dejar activos los frenos, encender las luces de emergencia…
Los sensores son de desaceleración y de impacto.
Procesos que vigilan los sensores y que detectan los casos de impacto.
Procesos que en función de lo detectado abren los airbags.
Y procesos que activan el resto de las cosas.
- Un SO para un celular de los años 90, no Smartphone.
Es un STR. Tiene que interactuar con la radiobase, detectar y gestionar el evento llamada. Y más nada porque los primeros celulares no tenían SMSs, pantalla de pixeles. Sólo una pantalla para ver el número.
Alto nivel: cerrado.
Nivel medio: inactivo, porque el sistema es muy simple.
A nivel bajo: scheduller a la medida, dada la simplicidad del aparato.
Gestión de Memoria
Caracterización de qué tipo de memoria… porque en realidad, TODAS interesan desde el punto de vista de la gestión de recursos.
- Memoria ROM
Sólo tiene lectura. Es de acceso aleatorio, es decir, cuesta lo mismo leer cualquier punto de la misma.
Para qué sirve la memoria ROM ?
No aparece en la arquitectura Von Neumann, con lo cual podríamos argumentar que no es una parte especialmente crítica de la computadora.
En la ROM vamos a guardar lo que no PODEMOS guardar en la RAM, ya que esta es VOLATIL.
Y no las puedo guardar en el disco secundario, porque preciso antes levantar el SO y las rutinas de entrada salida que logren interactuar con él…
En la ROM guardamos las BIOS, que es un conjunto de programas básicos, que, al encender la computadora, o el equipo de audio, o el auto, o el TV, o el Smart TV, etc, se copian de ROM a RAM y ejecutan.
Como parte de ese ejecución, van a detectar y chequear hardware, e ir a buscar el SISTEMA OPERATIVO al almacenamiento secundario.
Por esta razón la ROM siempre tiene unos pocos Kb.
Luego de que se levanta el SO, la computadora trabaja normalmente con RAM y con memoria secundaria.
- Por qué utilizamos memoria secundaria ?
La memoria secundaria tampoco está como elemento central e indispensable en la arquitectura Von Neumann…
La RAM es volátil. Además es cara y más escasa en relación al disco.
Necesitamos disco.
Ahí guardamos en forma PERSISTENTE, programas y datos del tipo que sean.
La memoria secundaria está más lejos que la RAM en relación a la CPU, pues no las vincula el bus principal, sino un bus secundario.
La única memoria directamente relacionada con la CPU es la RAM. Y es la única que la une el bus principal. Esto la hace la memoria principal del sistema.
Es la más rápida y más cara. Suele ser volátil.
El almacenamiento secundario, lo estudiaremos más adelante. Ahí el concepto principal son archivos y sistemas de archivos. Lo estudiaremos.
- Por qué se llama RAM la memoria principal ?
RANDOM ACCESS MEMORY, memoria de acceso aleatorio, que implica el mismo costo de acceso a cualquier dirección. En contraposición con cualquier dispositivo secuencial como las cintas.
- Por qué la memoria RAM tiene direcciones ?
Cuál es el elemento básico de almacenamiento de 1 bit ? BIESTABLE. Puede valer 0 o 1.
Cómo agrupábamos los biestables inicialmente ? Se agrupan en REGISTROS, que son de n bits.
Un registro, de n bits, tiene patas:
- Corriente
- Tierra
- Clock
- n patas de entrada
- n patas de salida
- una cantidad acotada de patas de control
Por tanto para un registro de n bits precisamos aproximadamente 2n patas
O sea que para un registro de 1 Gbit, que son 2**30 bits, precisaríamos 2**31 patas. Lo cual es una locura.
Una memoria de 1 Gbyte, tiene 2**30 direcciones de 8 bits cada una.
Precisa 2**33 biestables.
Pero como está direccionada, una memoria de 1Gbyte es una memoria de 1G x 8 o sea de 2**30 x 8
Sabemos que necesita:
- 30 líneas de dirección
- 3 líneas de control
- 8 líneas de datos.
- 3 líneas para corriente y clock
- Y algunas más eventualmente
Esto sume 44 líneas … y en función de n, queda aproximadamente log2(n)
Con lo cual queda un número mucho más lógica.
Entonces las direcciones nos sirven justamente para la reducción logarítmica de esta cantidad de patas.
POR ESO LAS MEMORIAS TIENEN DIRECCIONES.
- Qué rol juegan las cache ?
Los cache actúan como aceleradores.

El caché de CPU debe ganarle a la RAM. Está en la CPU mismo. Esta hecho de RAM rápida. Y combina múltiples niveles.
El caché entre RAM y disco debe ganarle al disco. Está en la controladora del disco. Está hecho de RAM lenta, común y corriente.
El cahé de red está hecho de disco local y busca ganarle a la LAN.
Y así sucesivamente.
Memoria y almacenamiento: SON LO MISMO.
Memoria Real y Memoria virtual: La MR la provee la arquitectura. La MV es una ilusión que provee el SO para que parezca ante los aplicativos, que la MR es mayor de lo que realmente es. La estudiaremos.
- Nuestro análisis será:
- Memoria Real.
- Memoria Virtual.
Vamos a ver más casos de asuntos en los cuales el SO va delineando la computadora tal como la conocemos.
Gestión de memoria (continuación)
MEMORIA REAL o principal o primaria o RAM
Es la memoria que está como componente principal en la arquitectura Von Neumann. Se comunica con la CPU por medio del BUS del sistema.
Almacenamiento y memoria son lo mismo.
Esta memoria contiene, a nivel de la arquitectura: programa en ejecución y datos para el mismo.
A nivel del Sistema Operativo, sabemos que ese programa en realidad corresponde a un conjunto de programas que forman parte de la multitarea. Y que van ejecutando por RR.
Es un recurso caro si se lo compara con la memoria secundaria.
Previo a la existencia de la memoria virtual y previo a la relativa abundancia relativa de memoria con que hoy contamos, la memoria RAM era un recurso a administrar muy cuidadosamente.
Hay dos asuntos en torno a la gestión de memoria:
ORGANIZACIÓN y ADMINISTRACIÓN de memoria.
Organización de la memoria:
Aspectos estáticos. Se fijan al arrancar el sistema.
Vamos a permitir múltiples procesos en la memoria ?
Qué lugar ocupa el SO en la memoria ?
La memoria va a estar dividida y de qué forma ?, a efectos de la multitarea ?
Qué pasa si un proceso invade a otro ? Protección de memoria.
La división en estas múltiples áreas destinadas a diferentes procesos, será estática o dinámica ?
Las secciones serán de igual o diferente tamaño ?
Las porciones de código irán contiguas o dando saltos en la memoria ?
Los trabajos se podrán ejecutar en cualquier parte de la memoria o en bloques determinados ?
Son todos asuntos a resolver, decisiones a tomar, que hacen a la Organización de la memoria.
Administración de la memoria:
Son los aspectos dinámicos. Ocurren con el sistema funcionando en régimen.
Cuándo traemos código o datos a memoria ? Esto se llama OBTENCIÓN. Se hará bajo demanda o en forma predictiva ?
En qué parte de la memoria alojamos lo que llega ? COLOCACIÓN.
Cómo gestionamos el espacio libre y los huecos ? COLOCACIÓN.
Si hay que hacer lugar por estar llena la memoria, quién sale ? Dónde va ? REEMPLAZO.
En el análisis de la administración de memoria tendremos 3 tipos de estrategias dinámicas (ocurren con el sistema funcionando):
- Estrategias de Obtención: cuándo traer a memoria RAM
- Bajo demanda vs Predictiva. O sea traer a memoria un programa y/o sus datos cuando solicitan su ejecución (obtención bajo demanda) o traer a memoria un programa y/o sus datos cuando el sistema predice que podría ser inminente su ejecución (obtención predictiva). Esto segundo se hace buscando mejorar la performance global del sistema, al ejecutar mucho más rápido. El riesgo es traer algo que luego no necesite, pues la obtención tiene un overhead.
- La obtención bajo demanda es lo usual, aunque hay tecnologías de predicción, por ejemplo el PREFETCH de Windows 10.
- Estrategias de Colocación: en qué parte de la memoria va lo que queremos guardar. Mejor ajuste, peor ajuste, primer ajuste. Son tres posibles estrategias. Las veremos.
- Estrategias de Reemplazo: si la memoria está llena, bajo qué criterio seleccionar quién sale, dónde se guarda, y de ese modo dar lugar a la información entrante. Veremos PEPS, NUR, NUR con segunda chance, LRU, LFU como posibles estrategias.
Un elemento a tener en cuenta es:
Organización jerárquica de las memorias.
- CPU y sus registros (más rápido, más pequeño, más caro).
- MEMORIA RAM (única memoria a una operación de distancia de la CPU, Mov)
- MEMORIA SECUNDARIA (un orden de magnitud más lenta (un cero más) que la RAM. Pero es más abundante y más barata.
Podemos combinar los niveles RAM y secundaria.
Otra decisión importante en la organización de la memoria es en relación al almacenamiento contiguo y no contiguo.
El primer caso refiere a bloques contiguos de código. Son más sencillos de gestionar pues se utiliza un espacio de direcciones adyacente y continuo, sin saltos; pero puede ser demasiado grandes y pesados.
En el segundo caso es más eficiente, pero está la complicación de saltar de un bloque a otro.
Aparecerá un nuevo problema que es la gestión de huecos en la memoria. Los huecos son los espacios libres. Los mismo pueden estar muy fragmentados y aparece otro nuevo problema, que es la fragmentación.
Esta fragmentación es en RAM, no tiene que ver con la fragmentación de archivos en disco, asunto que estudiaremos en unas clases.
Estudiaremos algunos mapas de memoria en diferentes situaciones.
- Asignación de memoria en un sistema operativo MONOTAREA y con Sistema Operativo Débil. Ejemplo: computadoras de los años 80s. ZX Spectrum (48Kbytes de RAM), Commodore 64 (64 Kbytes de RAM), etc.


Correr programas como el de la figura, en 48 Kbytes de RAM implicaba exprimir la memoria y en particular pasar por arriba del sistema operativo, que contenía un intérprete del BASIC.
El sistema operativo desaparece.
Qué pasaba al salir de un juego que sobreescribía el SO ?
Sólo se podía salir por la vía del………………………………. RESET.
Al resetear, se vuelve a copiar la ROM en la RAM, se pasa el control a esta, y levanta el intérprete de BASIC.
El tamaño de los programas no puede superar el tamaño de la RAM.
En este caso la gestión de memoria es trivial. NO hay multitarea y ni siquiera hay sistema operativo funcionando, entonces el único cuidado es en programar dentro de los límites de la memoria. Cualquier falla o transgresión al uso normal de recursos no será detectada ni gestionada por el SO pues no está. Entonces el que hará las veces de SO y capturará las interrupciones que correspondan es el propio juego. Los programadores resolvían su propia E/S porque había que exprimir la memoria.
- Asignación de memoria en un sistema operativo MONOTAREA y con Sistema Operativo FUERTE. Ejemplo: MS DOS.

El SO instalado en la parte baja de la RAM y sobre él el programa en ejecución, luego la memoria libre.
Aquí la idea es no aplastar al SO, por lo cual aparece un registro de límite, que apunte a la dirección “a” en la cual termina el SO en la memoria.
Entonces, si tenemos cualquier acceso a memoria, a una dirección entre 0 y a, se analiza si la misma corresponde, y si no representa una amenaza para el SO, y en tal caso se mata el programa.
Esto redondea la idea de SO fuerte, que no se deja desinstalar ni superponer.
El tamaño de los programas junto con el SO no puede superar la RAM.
Los registros de límites buscan delimitar y proteger al SO.

Una primera técnica para lidiar escasez de memoria…. OVERLAPPING o SUPERPOSICION MANUAL.
Cómo podemos ejecutar un programa que no entra en la RAM ? o que no entra en la RAM libre luego de alojado el SO ?
Una primera técnica sería instalarse arriba del SO, pero un SO fuerte no lo permite.
Una segunda técnica, más sutil, es el Overlapping.
En ella, el programa se va sobreescribiendo a sí mismo.
De esta forma, va logrando acomodarse dentro de una RAM que no puede contenerlo en forma completa.
Vamos a partir la memoria en 3 áreas:
- Sistema operativo (ni se entera ni gestiona ni forma parte de este truco)
- Core del programa. Este núcleo ejecuta y carga y descarga las partes variables.
- Área de superposición, donde se colocan las partes seccionadas del programa grande.
Así funcionan los juegos “multinivel”, que van cargando niveles, a medida que se avanza, en un área reducida de memoria.
Hay diferentes fases en la ejecución del progama:
- Inicio.
- Carga del CORE.
- Carga de la sección 1.
- Ejecución de la sección 1.
- Carga de la sección 2 anulando la sección 1.
- Ejecución de la sección 2.
- Etc.
El sistema operativo permanece, garantizando la integridad del sistema. El core permanece, garantizando las bases de la aplicación.
Esto permite ejecutar programas más grandes que la memoria RAM.
Complica la programación.
Es poco portable al ser muy dependiente de la arquitectura en concreto.
Difícil de mantener y modificar.
En la medida que la arquitectura permitió un mayor disponibilidad de memoria, se propició el MULTITASKING.
El mismo necesitó de tareas o procesos ejecutando a la vez y por tanto alojados en memoria RAM.
Esto induce la necesidad de crear PARTICIONES de memoria. Esto es dividir la memoria en bloques que serán asignados a diferentes programas.
Al hecho de que múltiples programas estén asociados a procesos que están ejecutándose concurrentemente, y por tanto estén estos programas alojados en memoria, se le llama, MULTIPROGRAMACIÓN.
Hay dos enfoques: particiones de memoria fijas y particiones de memoria variables.
La organización de la memoria en particiones fijas implicará la existencia de divisiones estáticas de memoria, las particiones.
Hay dos formas de gestionarlas: PARTICIONES FIJAS ABSOLUTAS Y PARTICIONES FIJAS CON REUBICACIÓN.
Como se ve, estamos analizando la multitarea, ya no desde la ejecución concurrente de procesos sino desde la asignación de memoria que propicia esta coexistencia de procesos.
Este requisito de tener más programas alojados en memoria requirió de una memoria mayor.

Continuaremos analizando las diferentes alternativas para esta gestión.

Tal como muestra la figura de más arriba, 7.6, tenemos un reparto bidimensional: 3 procesos concurrentes que se reparten la CPU por ejemplo por RR, pero también tenemos 3 filas de procesos que van accediendo a la memoria compartida vía PEPS.
(****) Los trabajos mencionados en los diagramas, son los programas que se desea ejecutar, y cuando el sistema logre alojarlos, serán procesos.
En este primer caso de traducción y carga absolutas, el compilador, cuando genera el código ejecutable, ya lo hace PARA QUE DICHO CÓDIGO SEA ALOJADO en UNA PARTICION DETERMINADA.
Ahora el compartir recursos es bidimensional: cada fila implica compartir memoria según PEPS seguramente. Y los que están alojados en memoria, comparten la CPU, según Round Robin, seguramente. Es un schedulling bidimensional.
Esto puede generar ineficiencias como la que sigue:

La partición 3 es muy popular, y las particiones 1 y 2 están vacías! Siendo las más grandes!
Esto genera un desperdicio.
La segunda alternativa, que es multiprogramación con particiones fijas, traducción y carga con reubicación, soluciona dicha situación.

Esto es más eficiente, se busca equilibrar las particiones libres. Pero el proceso de compilación es diferente. El compilador debe generar código máquina reubicable, es decir que corra en diferentes puntos de la memoria. Esto significa que hay un trabajo extra que hacer al momento de LOADING, de carga a memoria, que es terminar de fijar las direcciones de memorias de por ejemplo las variables, en función del lugar en que se aloja reubicablemente el código.
Por lo tanto la traducción es un poco más rápida, la carga es un poco más lenta.
Los códigos que se alojan en las diferentes particiones, no son de procesos necesariamente cooperativos, ni del mismo usuario. Entonces debemos proteger la memoria de accesos fuera de rango.
Si un código está alojado en determinada partición, no podrá acceder fuera de ella.
Si no, podríamos traer un programa que ataque a los demás o al SO.
Qué pasa si un programa no entra en la partición que le toca ? Dejamos pasar al siguiente.
Y si no entra en ninguna ? No debimos dejarlo pasar, o sea, no se lo deja pasar.
Cómo diferenciamos los claramente prioritarios procesos del SO ? Levantan al comienzo, por ejemplo el scheduller.

‘ Entonces para lograr esto usaremos los llamados registros de límite, que tienen el borde superior e inferior de la partición que en ese momento está ejecutando.
Con ellos cuidamos que los procesos no se ataquen entre sí ni al SO.
Por ejemplo: cada vez que el proceso alojado en la partición 2 intenta acceder a una zona de memoria x, se fija que x caiga en el rango de direcciones de la partición 2. En este caso b<=x<c.
FIN DE MULTIPROGRAMACION CON PARTICIONES FIJAS.
En la multiprogramación con particiones AHORA VARIABLES, aparece el problema de los huecos.
Los huecos implican que el espacio libre aparezca fragmentado, muy dividido, y eventualmente no pueda ser aprovechado totalmente o incluso utilizado.
Supongamos que tenemos un conjunto de pedidos de bloques de memoria, los cuales asignaremos en base a multiprogramación con particiones variables.

Aparece una gran ventaja que es que les vamos destinando la cantidad justa de memoria.
PERO esos procesos van a terminar! Y ahí generan huecos.

A medida que los procesos van terminando vamos pasando de una situación “perfecta” (cada proceso tiene lo que pidió y sin sobrantes) a una situación “más compleja” con emergencia (van emergiendo) de huecos.
Hay dos técnicas que se pueden aplicar: condensación y compactación.

En la condensación unimos huecos ADYACENTES.
Como son huecos libres, y no muevo nada, este método es inofensivo.

La compactación implica mover código (OJO código en ejecución!!!!!!) y así generar situaciones de nuevo orden.
Pero mover código de programas en ejecución es muy complicado. Hay que detener la ejecución. Y eso no es deseable.
FIN DE LOS MAPAS de ASIGNACION DE MEMORIA
Estrategias de colocación.
Cuando tenemos un conjunto de bloques libres de diferente tamaño, y llega una petición, hay que elegir qué bloque asignaremos.
Hay 3 criterios:
- Mejor ajuste
- Peor ajuste
- Primer ajuste

Viene un pedido de 13K , el primer ajuste, significa que el primer bloque libre capaz de contener esos 13K, lo asigno. Y este es el bloque de 16K. Medida del desperdicio: 3K. Se genera un nuevo bloque libre de 3K que es muy chico.

El mejor ajuste busca minimizar el desperdicio y elije el hueco de 14K. El nuevo hueco generado es de 14-13=1K. Muy chico, no sirve para más nada.

Busquemos el hueco más grande. El mismo es de 30K. 30-13=17K libres. Este nuevo hueco sirve. Pero me quitó el hueco más grande!
Vamos a ponderar las tres estrategias.
Mejor ajuste: hay que minimizar el tamaño del nuevo hueco libre, por tanto requiere revisar TODOS los huecos. El nuevo hueco generado sirve poco por ser muy chico.
Peor ajuste: hay que maximizar el tamaño del nuevo hueco libre, por tanto requiere revisar TODOS los huecos. Se lleva rápido los huecos grandes!
Primer ajuste: se lleva el primer hueco que soporte la solicitud. En el peor caso reviso todos los huecos, pero no siempre. Por tanto es un poco más ágil. Encima las ventajas del mejor y el peor ajuste no están claras, con lo cual concluimos que esta estrategia parece la mejor de las tres, a priori.
FIN DE MEMORIA REAL.
La memoria virtual surgió como una necesidad por la escasez de RAM. Hoy no es así, y queda relegada a casos de emergencia. Sin embargo el esquema de direccionamiento y de organización de la memoria virtual, sirve para la memoria, se use la parte no RAM o no se use.
Es lo que se usa.
Lo vamos a estudiar.

En la figura se muestra la evolución temporal de la gestión de memoria.
La memoria virtual llegó después. Y actualmente predomina la paginación pura, si bien no es el esquema más sofisticado. Linux utiliza paginación básicamente.
La memoria virtual consta de la RAM más un poco de disco. Se gestiona como un todo, dando la ilusión de que se dispone de más memoria que la RAM.
Actualmente se usa poco la parte disco de la MV, incluso se configura para desactivarla, pero la división de la memoria en páginas, etc, es la forma moderna de direccionar memoria.
Lo estudiaremos en cuánto organización y administración.
ORGANIZACIÓN DE LA MEMORIA VIRTUAL
La idea es proporcionar un espacio de direcciones mayor que la memoria Real. Al gestionar la MV el SO, se “estandarizó” el overlapping. Recordemos que era el alojar y desalojar de memoria principal partes de programas y datos… ahora un mecanismo “escondido dentro” del SO resolverá ese cargar y descargar, sin que el usuario o el programador deba preocuparse por los detalles.
La MV pasa a ser otra ilusión que el SO provee.
Vamos a tener que gestionar la ilusión de que el espacio de direcciones VIRTUAL es mayor al espacio de direcciones REAL.
Necesitamos una función de traducción de direcciones virtuales (las que ofrece el sistema operativo) en direcciones reales (las que acepta la arquitectura).
La idea es la siguiente: se toma TODA la memoria RAM y se toma algo de disco (por ejemplo tanto como la memoria RAM) y se arma un todo.
Esa memoria total, por ejemplo MV=64 Gb = 32Gb RAM + 32 Gb disco es la memoria virtual.
Para acceder a la memoria nosotros debemos acceder a la memoria real, la arquitectura no ve otra memoria que la real… entonces los datos al momento de ser accedidos, van en memoria RAM…. Eventualmente hay que “salir corriendo” a moverlos si estaban en disco.
Qué es mejor: que un dato esté en RAM o en disco? cuál es más rápido: la RAM, es un orden de magnitud más rápido, es decir 20, 30, 60, 70…. Un cero más… Entonces aquí aparece el precio a pagar por tener una memoria (simulada) más grande: el overhead, por acceder a disco, que es más lento, y por la algoritmia detrás de la gestión de memoria.
En abstracto: sacrificamos velocidad (tiempo) para ganar memoria (espacio).
Volvamos al concepto del espacio virtual de direcciones.
Necesitamos una función de traducción que dada la dirección virtual nos dé la dirección real.
Una función puede ser una tabla ?
Una función de A en B es una relación R incluida en el A x B, tal que si aRb y aRb’ entonces b=b’. Si es función es subconjunto del producto cartesiano, entonces es conjunto. Los conjuntos se pueden dar por extensión y por comprensión. Entonces las funciones se pueden dar por extensión o por comprensión. Por ejemplo: f(x)=x+log(x) está dada por comprensión.
O en el AB f(a,b)=a NOR b está dada por comprensión… pero puedo darlas por extensión, cuando el dominio lo permite.
f(0,0)=1
f(0,1)=0
f(1,0)=0
f(1,1)=0
Ahí dimos una función NOR por una tabla…
Analicemos la FUNCIÓN DE TRADUCCIÓN DE DIRECCIONES VIRTUALES EN REALES.
Su dominio es… el espacio VIRTUAL (discreto y finito), y su codominio es el espacio REAL. Puedo darla por medio de una tabla.
Y tendríamos que decir, para cada dirección virtual cuál real le corresponde.
Podemos dar una tabla para dar la tal función de traducción, por extensión ?
Damos una tabla, del lado izquierdo ponemos la dirección virtual, y del lado derecho la real correspondiente, así para todas las direcciones.
Esa tal tabla, llamémosle tabla de correspondencia de direcciones…
Qué largo esa tabla? EL LARGO ES EL TAMAÑO DE LA MEMORIA VIRTUAL.
Qué problema ven?
QUE ESTA TABLA, QUE NOS DICE PARA CADA DIRECCIÓN VIRTUAL, DÓNDE ESTÁ LA REAL, ES TAN LARGA COMO LA MEMORIA VIRTUAL. ENTONCES SI LA ALOJO, OCUPO TODA LA MEMORIA. O SEA, ES INMANEJABLE, INVIABLE…
Entonces la solución es RENUNCIAR A LA TRADUCCIÓN INDIVIDUAL DE DIRECCIONES. En lugar de ello trabajaremos con direcciones bidimensionales en bloques y desplazamiento dentro del bloque. Solo guardaremos dónde está cada bloque.
Vemos la memoria virtual como un conjunto de bloques. Algunos están en RAM y otro en disco. Tenemos que guardar dónde está cada bloque.
Los bloques tienen la ventaja de ser subconjuntos contiguos, que se tratan como una unidad, y que es cómodo por ejemplo alojar código en ellos. Llevaremos una tabla MUCHO MAS CHICA, que nos dice dónde está cada bloque. Esa tabla es la TABLA DE CORREPONDENCIA DE BLOQUES.
Las direcciones pasan a ser bidimensionales, es decir (bloque, desplazamiento).
El desplazamiento es una dirección relativa dentro del bloque.
En la memoria RAM las direcciones son unidimensionales… por ejemplo decimos la dirección 14F5h…
En la memoria Virtual, las direcciones son bidimensionales…. Por ejemplo (5,14h). Es decir el bloque 5, y dentro de él la dirección 14h
Tenemos que traducir MV en MR. Dimensión 2 en dimensión 1.
Estos bloques pueden estar en memoria RAM o en memoria SECUNDARIA. Y se mueven constantemente entre uno y otro. Nuestros algoritmos de traducción y de administración deben trabajar con eso.
Los bloques pueden ser páginas o segmentos. Las páginas son de largo fijo y los segmentos son de largo variable.
Cuando un bloque pasa de RAM a Disco y otro de disco a RAM, alternando sus posiciones, decimos que ocurrió un SWAP.
Cuando se acceda a la memoria virtual en su parte que es disco, necesariamente ocurrirá un swap.
Cuando se vaya a trabajar con un bloque que está en MV, este puede estar en MR o no. Si está en MR aplicamos un mecanismo de traducción que estudiaremos.
Si está en MS, ocurrirá un SWAP.
Estudiaremos SWAPS y traducción la clase que viene.
Cuando una computadora tiene memoria RAM que le está quedando chica respecto al uso que se hace de ella, y tiene una memoria virtual configurada, comienza a aumentar el número de los accesos a la parte secundaria de la memoria virtual (la mentira!). Entonces aumentan los swaps. Entonces cuando estamos trabajando, observamos que se prende más veces la luz del disco al tiempo que notamos un deterioro en la performance.
Y decimos… “la máquina está …. SWAPPING O swappeando”… y lo curamos… AUMENTANDO LA RAM.
Estudiaremos o volveremos sobre el comentario de este fenómeno…
Continuamos con Memoria Virtual
Estamos estudiando la memoria virtual.
Habíamos visto que la traducción de virtual a real con una tabla entera, dirección a dirección es imposible, no hay donde alojar una tabla que es tan larga como la MV.
Entonces trabajamos con bloques.
Los bloques pueden ser páginas o segmentos según si son de largo fijo o variable respectivamente.
Las direcciones pasan a ser bidimensionales: <bloque, desplazamiento>
Y tenemos que traducirlas a direcciones unidimensionales sobre RAM.
Los bloques componen la MV y están en MR o en MS.
Los bloques que ya están en RAM no necesitan más nada para ser accedidos. Sólo hay que dar la dirección traducida.
Los bloques que están en MS, necesitan, previo a la traducción, venir a la RAM. Pero la RAM está llena de otros bloques. Entonces elegimos uno que sale, y los “SWAPEAMOS”, los intercambiamos. Esta operación, el SWAP, es clave en todo esto.
La memoria virtual combina dos niveles de almacenamiento: RAM y Disco. Debido a sus diferencias de precio, tamaño y velocidad.

La figura anterior nos muestra como los bloques de memoria virtual se mapean dinámicamente sobre la RAM.
La traducción de direcciones debe hacerse en Runtime y en tiempo real.

Tal como nos muestra la figura, el orden en memoria virtual no tiene nada que ver con el orden en memoria real y de hecho ni siquiera se mantiene, varía constantemente debido a la ocurrencia de swaps.

La contigüidad artificial es una propiedad que nos indica que la memoria virtual tiene una falsa contigüidad, es decir que se mapea sobre otro orden en MR y que varía constantemente.
El orden dentro del bloque siempre se mantiene. Pero los bloques se mueven.
Las direcciones de la figura anterior se ven como contiguas y no tienen por qué serlo.
Vamos a profundizar en la traducción de direcciones VIRTUALES a REALES.
Debemos traducirla en términos de una dirección r de RAM.
Para ello debemos saber si: el bloque b está en RAM, y en tal caso dónde comienza, y a ese comienzo sumarle d. Si no está en RAM necesitamos ubicar dónde está en la memoria secundaria, y realizar un swap.

Esta tabla de correspondencia de bloques guarda toda la información relativa a cada bloque, o sea:
Para guardar esta información usaremos la tabla de correspondencia de bloques.
- Id de bloque b.
- Bit de residencia r. Si r=1 entonces es que el bloque correspondiente está en RAM, si no, está en disco.
- Si el bloque está en RAM (r=1) entonces la tabla guarda en DirRAM la dirección RAM donde el tal bloque comienza.
- Si el bloque está en disco (r=0) entonces la tabla guarda en DirDisco la dirección del bloque en disco.
- Eventualmente guardamos también otros atributos relevantes del bloque.
Esta tabla debe residir en RAM y es VITAL en el funcionamiento de la memoria virtual.
Cómo traducimos, teniendo esta tabla, las direcciones?
Sea a el punto base de la memoria a partir del cual la tabla está almacenada.
Sea k el ancho en bytes de la tabla.
Entonces en a arranca la información del bloque 0
Entonces en a+k arranca la información del bloque 1
…
Entonces en a+i.k arranca la información el bloque i-ésimo.
…
Cuando tenemos una dirección virtual de la forma <b,d>, hacemos lo siguiente.
- Vamos a la dirección de comienzo del b-ésimo bloque, la cual la obtenemos de la tabla de correspondencia de bloques, en la entrada a+b.k
- Consultamos el bit de residencia [a+b.k].r.
- Si [a+b.k].r=1, entonces sabemos que el bloque está alojado en RAM y que su dirección de comienzo es [a+b.k].dirRAM
- Si [a+b.k].r=0 entonces sabemos está en disco.
- En este caso se levanta una interrupción llamada de FALLA de página. PAGE FAULT.
- Y como respuesta al PAGE FAULT ocurre un SWAP, entre el bloque b y algún bloque seleccionado para salir de acuerdo a la política de reemplazo existente.
- Para hacer este swap necesitamos la dirección del bloque en disco, la cual es [a+b.k].dirD
- Luego de ocurrido el page fault y su swap, el bloque b estará en RAM, y por tanto estará a partir de la dirección [a+b.k].dirRAM
- Entonces haya ocurrido swap o no ya tenemos el bloque en RAM y a partir de la dirección [a+b.k].dirRAM.
- Para completar la dirección real correspondiente tan sólo resta sumarle el desplazamiento. [a+b.k].dirRAM+d
Con todo este algoritmo logramos la traducción de direcciones virtuales en reales.
Si los bloques son de largo fijo, se llaman PÁGINAS.
Las páginas tienen una ventaja.
Sea p el largo de página.
Entonces la memoria real y virtual van a ser “cuadriculadas” en términos de bloques de largo p.
Por tanto las posibles páginas de memoria, irán de:
0..p-1 la página 1
p..2p-1 la página 2
2p.. 3p-1 la página 3
…….
La página i irá de (i-1).p .. ip-1
A estos contenedores de posibles páginas se les lama marcos de página.
Entonces la dirRAM; no tiene que ser una dirección completa, sino apenas el número i correspondiente al i-esimo marco de página.

O sea que en la TCB (tabla de correspondencia de bloques) guardaremos que la página PAG, de largo p, se almacenará en algún marco de página i.
No precisamos guardar toda la dirección física.
Entonces tenemos que hay una tabla, la TCB, tabla de correspondencia de bloques, alojada en RAM, que está jugando un rol central en esta traducción. El acceso a esta tabla es una operación tan frecuente, que quisiéramos optimizarla.
Tenemos 3 alternativas para esta tabla.
Caso 1: toda la tabla guardada en RAM.

Caso 2: toda la tabla guardada en una memoria especial, aparte, más rápida que la RAM.

Caso 3: parte de la tabla guardada en una memoria especial pequeña, un caché, y el resto en RAM. Este último es más realista que el caso 2.

Las páginas y segmentos pueden compartirse. Basta apuntar a las mismas desde diferentes procesos.
Obviamente se pueden manejar un esquema de permisos de acceso.
Los segmentos son bloques de largo variable… en qué cambia todo esto?
Segmentación….. en este caso los bloques son de largo variables.
Por lo pronto hay que guardar al menos el largo de bloque en la TCB.
Se debe llevar la cuenta de los bloques libres y sus largos. Esto es más complejo.
La TCB a menos de guardar el largo de bloque, es idéntica.
El algoritmo de traducción de direcciones es idéntico, y también acepta tener caché.
Tanto páginas como segmentos pueden tener permisos de acceso, locuales se guardan en la TCB, y son básicamente Read, Write, Execute… se pueden dar individualmente para cada usuario sobre la página.
Los segmentos además pueden tener permiso para Extenderse, no olvidemos que son de largo variable, a diferencia de las páginas.
Los bloques también tendrán dueño y tal vez algún esquema de permisos como al anterior.
Entonces según el usuario que está ejecutando, según el permiso de acceso a las páginas que tendría (las suyas). Esto se puede arbitrar buscando la seguridad del SO.
Entonces en caso de usar segmentos, el cabezal de la tabla TCB podría ser de este tipo:

Por último, podríamos combinar segmentos con páginas, haciendo referencia a segmentos que contienen dentro páginas… en un esquema tridimensional de direcciones, donde una dirección sería una terna <segmento, página, desplazamiento>.

Esto es más complicado y normalmente se usa paginación.
FIN DE ORGANIZACIÓN DE MEMORIA VIRTUAL.
Preguntas para discutir algunas ideas extra.
- Por qué razón podríamos querer desactivar la memoria virtual de un SO genérico?
Lo interesante es desactivar la memoria virtual. Pero sin perder su mecanismo de direccionamiento. Porque es la forma más eficiente de tener múltiples procesos alojados en memoria.
Podríamos tener requisitos de performance, tiempos de respuesta, y con la parte Real de la MV se cumplirían, pero con la parte de disco de la Memoria Real no se cumplirían…
Podríamos tener escenarios de abundante RAM o de disco muy pequeño y/o dedicado a algo.
En general, un SO es genérico, pero hay escenarios donde tal vez yo pueda fijar características específicas. Por ejemplo si sobre el SO va a correr algún tipo de STR. En esos escenarios podemos necesitar tiempo de respuesta rápido y podemos determinar que no vamos a necesitar entrar en la parte de disco de la MV, y ahí podríamos desactivarla.
Para desactivarla se hace coincidir MV=RAM.
Entonces conservamos el mecanismo de multiprogramación… de alojar en memoria en simultáneo procesos concurrentes.
- Por qué razón podríamos querer mantener acotada la parte de disco que participa de la MV ?
En Windows, la parte de disco de la MV, va en un archivo /pagefile.sys.
En Linux va en un directorio /swap que usualmente es una partición separada.
Esto de acotar el largo máximo de la parte de disco de la MV es típico en Windows y Linux. En la actualidad no se pasa más allá de proporciones 1 a 1. Por ejemplo 16Gb RAM + 16 Gb Disco.
Lo mantendríamos acotado para evitar un enlentecimiento descontrolado producto de la cantidad de swaps. En definitiva proponemos una degradación gradual de la performance pero no más allá de cierto límite. Y ese límite lo marcamos no aportando más disco que el tamaño de la RAM, por ejemplo.
Si el archivo o partición de swap, según el caso, crecieran descontroladamente de todos modos no sobreescribe archivos, etc.
- Por qué la TCB se guarda en RAM ?
Esta tabla se accede constantemente, así que por eficiencia, y también por funcionamiento, ya que la MV depende ella.
- Cómo influye en el multiusuario el acceso a las páginas de memoria ?
Si el sistema es multiusuario, y una página aloja código o datos, éstos serán de determinado usuario y para todos los demás y para él, aplicará un esquema de permisos.
Administración de la memoria virtual
La administración de la memoria abarca los asuntos dinámicos, es decir la computadora funcionando en régimen.
Administración de memoria implica:
- Estrategias de obtención: CUÁNDO TRAER LA PRÓXIMA PÁGINA O BLOQUE DE MS A MR. Bajo demanda o anticipada.
- Estrategias de colocación: DÓNDE VA. LOS MARCOS DE PÁGINA SON TODOS IGUALES, ASÍ QUE EN PAGINACIÓN LA ESTRATEGIA DE COLOCACIÓN, DA LO MISMO, es trivial…
- Estrategias de reemplazo: QUIÉN SALE PARA HACER LUGAR. SI LA MEMORIA RAM ESTÁ LLENA DE PAGINAS, CUAL SALE PARA DAR LUGAR A UNA NUEVA Y ASÍ HACER UN SWAP.
Vamos a analizar las diferentes estrategias DE REEMPLAZO.
- Principio de optimalidad: quitemos de MR la página que va a demorar más tiempo en ser accedida. Y cómo sé cuál es esa tal página ? NO LO SE NI TENGO FORMA DE SABERLO por tanto el método de optimalidad es IMPOSIBLE DE IMPLEMENTAR, ES UN IDEAL INALCANZABLE. o
- Reemplazo aleatorio: CUALQUIERA. En informática lo aleatorio es difícil de lograr, tenemos lo pseudoaleatorio, que no es lo mismo, con lo cual aparece el riesgo de aplazamiento indefinido, etc.
- Reemplazo PEPS. Hacemos una fila de acuerdo al momento en que fue traída la página de MS a MR y expulsamos a la más antigua. Expulsa igual al scheduller. Es una técnica muy primitiva.
- Reemplazo LRU (least recently used). Llevamos una marca, un timestamp, en cada página, de cuál fue la última vez que la accedí… y expulsamos a la que lleva más tiempo sin ser accedida. Podría estar justo sacando una página que le iba a tocar ser accedida. O podría estar justo sacando una página que es muy accedida, y que justo circunstancialmente fue determinada para salir por el LRU. Tienen un overhead importante.
- Reemplazo LFU (least frequently used). Llevamos una contabilidad de los accesos por unidad de tiempo, para tener la frecuencia. Es más costoso de mantener, o sea, tiene más overhead y además tiene el mismo problema que LRU, es decir que podría estar sacando una página que necesitamos en RAM.
- Reemplazo NUR (no usada recientemente). Llevamos un array de booleanos, uno por cada página. Arrancan todos en false. Cada vez que se accede una, ponemos en true. Cada tanto reseteamos todo a False. Cuando debe salir una página SORTEAMOS entre las NO ACCEDIDAS. Es más simple, es más liviano, puede ser poco preciso.
- Reemplazo NUR con segunda chance. Muy parecido a esto hace Linux… Guardamos 2 booleanos por cada página. Marcamos el primero en el primer acceso y el segundo en el segundo acceso. Cada tanto reseteamos. Si tengo que sacar una página armo un SORTEO PONDERADO. Las páginas que fueron accedidas 2 veces, no van al sorteo. Las que fueron 1 vez van con una chance, y las que fueron accedidas 0 veces van con 2 chances…
NUR y NUR con segunda chance tienen el mérito de ser ágiles! Tienen la desventaja de ser sorteos… pero es lo usado.
Un asunto extra: LA ANOMALÍA PEPS.
Supongamos que hacemos REEMPLAZO según PEPS.
La página que sale es la más antigua.
Sin embargo esta anomalía nos muestra un caso, bajo PEPS, que aumentando la RAM igual los swaps aumentan.
Es un caso curioso… hiper particular.

Principio de Localidad REFERENCIAL
Supongamos que graficamos, en una computadora cualquiera, los accesos a memoria virtual. Es decir cada vez que una dirección es accedida, nosotros pintamos esa dirección con un punto, o algo así.
En teoría, podríamos esperar que la distribución de los accesos fuera uniforme, con probabilidades iguales de acceso a cualquier punto de la memoria.
SIN EMBARGO, LO QUE SE OBSERVA, NO PODRÍA ESTAR MÁS ALEJADO DE ELLO.
Experimentos empíricos, han mostrado que se accede a la memoria en PATRONES ALTAMENTE LOCALIZADOS. No es equiprobable ni cerca el acceso a MV.
Por qué puede pasar esto ? Porque el código de un loop se repite muchas veces. También una estructura que se recorre, se repite muchas veces el acceso…
El principio de localidad nos dice que los accesos a memoria se dan en patrones no uniformes y altamente localizados.
Como corolario, tenemos que cada proceso va a tener, al ejecutarse, un conjunto de páginas “favoritas” que tenderá a favorecer en el acceso. Estas tienden a ser adyacentes en el espacio virtual.
Entonces cada proceso tiene sus páginas favoritas. Les llamaremos el WORKING SET del proceso.
Aquí aparece una técnica de obtención PREDICTIVA, basada en traer a memoria principal, para cada proceso, su working set.
Estrategias de obtención
- Paginación por demanda: la página que es accedida es la próxima a alojar en MP.
- Paginación anticipada: trata de anticipar la necesidad, trayendo en forma predictiva, páginas de MS a MP. Cuáles ? POR EJEMPLO, UNA POSIBLE ESTRATEGIA, ES TRAER EL WORKING SET DE UN PROCESO.
El tamaño de página…
Páginas muy pequeñas alargan la tabla TCB y la tornan inmanejable, llenan de overhead.
Páginas muy grandes generan swaps muy costosos y restan agilidad.
Entonces hay un tamaño de compromiso entre ambas, por ejemplo del orden de algunas de decenas de Kb que permite trabajar razonablemente. Las memorias actuales tan grandes requerirían de bloques mayores…
No es un óptimo, pero se fija y testea empíricamente.
La localidad referencial sugiere páginas relativamente chicas.
Una medida empírica de los Working Set puede ayudar a configurar el tamaño de página.
La idea es tener una tabla TCB de un tamaño razonable por un lado, y no tener swaps costosos en tiempo por otro.
Tener una tabla TCB chica me lleva a tener bloques grandes por un lado.
Por otro lado buscar swaps ágiles nos lleva a tener bloques más pequeños.
De todo se deduce un tamaño óptimo de página… óptimo empírico… es decir ajustamos valores y los probamos…

La gráfica de más arriba nos muestra las esperas por páginas…
Del punto de vista del total del sistema no hay problema, porque un proceso que espera por un page fault, espera bloqueado, no hace uso de CPU y por tanto no influye negativamente en el desempeño del mismo.
Pero por otro lado, si examinamos las esperas, que nos las muestran las barras BLANCAS, en relación a la ejecución (las barras NEGRAS) notamos que los PAGE FAULT degradan notoriamente el desempeño del proceso individual, retrasan su ejecución.
Almacenamiento secundario
Dos asuntos que analizar.
Primero es la gestión física del almacenamiento secundario. Esto es un tema más que nada de arquitectura, aunque históricamente, estuvo a cargo del SO, hoy embebido en la controladora del disco.
Segundo y más importante es la gestión de los file systems, y de los archivos. Esto involucra las estructuras que provea el sistema operativo para gestionar archivos, permisos y el multiusuario.
Por qué el almacenamiento secundario es secundario ?
Porque el almacenamiento primario, que es el que ve “directamente” la CPU a través del bus, es la memoria RAM.
Aquí se utiliza un bus secundario, el cual llega a la CPU a través de los esquemas de interrupciones.

La memoria está conectada a través del northbridge y el disco a través del southbridge. El primero es el bus “Von Neumann”.
https://thehittoslab.blogspot.com/2013/11/placa-base-northbridge.html


Por qué precisamos el almacenamiento secundario ?
Tamaño y precio (el costo por byte es mucho menor que la RAM y entonces tenemos más grandes)
Persistencia (la RAM habitualmente es volátil)
Velocidad (es más lento que la RAM)
Qué tecnologías tenemos para el almacenamiento secundario ?
Cintas magnéticas (secuencial … hoy backups).
DISCOS HDD (más baratos) Esta tecnología está saliendo…
DISCOS DE ESTADO SÓLIDO (más rápidos, más caros, más robustos, consumen menos)
HIBRIDOS (OPTANE, etc)
CDs y DVDs Son ópticos, son extraíbles… NO SON “LECTOESCRIBIBLES ON LINE” al DVD o lo estoy quemando o lo estoy leyendo. No puedo guardar un Word que grabo cada 5 minutos acá…. Son para entregar un software… canciones, películas.
Pendrives, memorias SSD etc.
https://www.youtube.com/watch?v=E7Up7VuFd8A Video sobre el funcionamiento de una SSD.
Disquetes (1,44Mb) , Discos ZIP (100 Mb) y JAZZ (1 Gb)… nunca cuajó… por caros, por inoportunos, por no entendidos… la gente los confundía con los CDs… en cuanto a su uso.
Pero el Disquete, el ZIP y el JAZZ soportaban lectoescritura on line….
Hoy tenemos la nube.
Nos vamos a detener en analizar un poco más los discos HDD mínimamente. Y luego vamos a pasar al análisis de FILE SYSTEMS y ARCHIVOS, que es transversal a todas las tecnologías anteriores.
Vamos a estudiar un poco el acceso a los datos en Disco.
La lógica del disco antes estaba como parte del SO. Actualmente está embebida en la tarjeta controladora del disco. Este es uno de los asuntos que el nivel de SO pasó a la arquitectura.
El file system SÍ ES DEL SO.
Un disco HDD tiene múltiples caras, cada una es leída por una cabeza. Todas las cabezas se mueven juntas. El disco gira, por ejemplo a 7200 rpm. Los hay más lentos y más rápidos.
Cada cara es una superficie magnetizable y de esa forma puede guardar ceros o unos según cómo se aplique la corriente. En forma PERSISTENTE.
Cada cara tiene un conjunto de pistas concéntricas.
Cada pista está dividida en sectores, que constituyen la unidad de acceso.
La capacidad de un HDD se obtiene multiplicando:
Caras por disco x pistas por cara x sectores por pista x bytes por sector
Las cabezas se mueven todas juntas.

- El tiempo de acceso a disco se descompone en:
- Tiempo de búsqueda (el brazo ubica la pista, es el más lento de los 3)
- Tiempo de latencia (el disco gira y así se ubica el sector correspondiente)
- Tiempo de transmisión (lectura y transmisión de la información)
- Todos estos tiempos son lentísimos comparados con los tiempos de CPU. Entonces son un cuello de botella para el desempeño del sistema, y por ello es preciso optimizarlos.

- Como todas las cabezas se mueven juntas, lo más conveniente es ubicar la información según cilindros consecutivos, que resultan de considerar el brazo en una posición fija dada.
- Un cilindro es un conjunto de pistas en todas las caras del disco, considerando la cabeza quieta sobra dichas pistas y el disco girando.
Cuando desfragmentamos los archivos se reubican de forma compatible con la geometría del disco, es decir en cilindros consecutivos.
Si el tiempo de acceso a datos en disco es la suma de estos tres tiempos, vamos a analizar cómo optimizarlo.
El tiempo más lento es el tiempo de búsqueda y por tanto su optimización será la de más impacto.
Entonces nos preguntamos en qué medida podemos REORDENAR (para mejorar los tiempos) las respuestas o atenciones a solicitudes de datos o de acciones de escritura que vinieran llegando.
NO hacer nada respecto a la optimización sería atender FIRST COME FIRST SERVED….
- FCFS: First come first served, se atienden los pedidos en el orden en que llegan.
- Problemas al variar las peticiones entre los patrones más internos y los más externos:
- Ej.: O 2 – 4- ———————— 3-1
- El reordenamiento de la hoja de solicitudes se conoce como PLANIFICACION DE DISCO.
- La planificación de disco consiste en analizar y reordenar las solicitudes pendientes.

Estos datos van a la controladora. Se genera una interrupción y al ser atendida se comunican.
Acá algo rompe los ojos… es que estamos pasando por donde están los datos pero como el orden no lo indica, no los recogemos.
Optimizar el acceso a los datos en disco es reordenar la hoja de solicitudes.
- Las más comunes:
- Optimización de búsqueda
- Optimización rotacional (de latencia)
- Los tiempos de búsqueda son un orden de magnitud mayor que los de latencia, por lo que las primeras son las principales.
- En condiciones de carga ligera, FCFS trabaja bien, pero si el sistema es exigido, se notan los problemas.
Planificación de disco serán las formas que tendremos de reordenar la hoja de solicitudes.
Características que pediremos a las políticas de planificación de disco:
- Tratamiento justo a todas las solicitudes.
- Evitar el aplazamiento indefinido.
- Maximizar la productividad, esto es la cantidad de accesos por unidad de tiempo.
- Minimizar el tiempo medio de respuesta.
- Minimizar la varianza del tiempo medio de respuesta. A menor varianza tendremos mayor predecibilidad.
La varianza indica cuánto nos alejamos de la media, del promedio o del valor esperado.
Algunas políticas de planificación de disco:
- FCFS: FIRST COME FIRST SERVED primero que llega es el primero que se atiende
- SSTF: SHORTEST SEARCH TIME FIRST primero el menor tiempo de búsqueda, el brazo se traslada a la petición que requiere movimiento mínimo.

Es más rápido pero tiene más overhead. Hay que calcular un mínimo o máximo cada vez.
- SCAN: el brazo se mueve hacia adentro y hacia fuera, atendiendo todas las peticiones a su paso.
- C-SCAN: Como SCAN pero cambia el sentido en cuanto no encuentra más peticiones en esa dirección.
- Scan de N pasos: El brazo del disco se mueve igual que en SCAN, pero las peticiones que llegan durante el barrido en una dirección se almacenan y reordenan para darles un servicio óptimo durante el barrido de retorno.
Los HDD usan una especie de C-scan de n pasos.
Optimización rotacional… busca minimizar la latencia:
- Cuando la carga es pesada aumenta la probabilidad de múltiples referencias al mismo cilindro, por lo que toma sentido la optimización rotacional.
- SLTF:SHORTEST LATENCY TIME FIRST Primero el tiempo de latencia más corto. Una vez que la cabeza llega a cierto cilindro, los pedidos sobre el mismo se atienden según el criterio de tiempo de latencia más corto.

Usamos memoria auxiliar para reordenar la lectura de los datos de la pista. Yo sé que 4 2 y 3 me los van a pedir, entonces ya los guardo.
Luego, al leer el pedido 1, ya saco de memoria (caché disco o RAM) y entrego el resto de las lecturas.
- Reorganización del disco para minimizar fragmentación de archivos. Usaremos la geometría natural del disco, es decir cilindros consecutivos.
- Memoria caché de disco. Para acelerar accesos y ejecutar algoritmos de optimización reordenando solicitudes como vimos.
- Sistemas de discos múltiples. Tratamos un conjunto de discos como una sola unidad. RAID. Usamos un esquema de redundancias que nos permita por ejemplo salir andando en caliente en caso de rotura de un disco. El caso más simple de RAID es el mirroring. Esto mejora la robustez general al darle tolerancia a faltas individuales en los componentes. Arrays de discos hot swap…
- Discos RAM
- Son una parte de la RAM accedida vía file system.
- En algún momento se usaron para casos de borde, como no tener disco duro
- Algunos instaladores han usado para optimizar.
- Poco usado actualmente.
FILE SYSTEMS
Hay un file system por cada partición de disco.
Qué son las particiones ?
Son divisiones lógicas, de BAJO NIVEL, del disco. Están por debajo del file system. Se comportan como un disco independiente. Ningún archivo puede crecer más que la partición que lo contiene.
Esto puede dar robustez.
SIN FILE SYSTEM no hay multiusuario, ni seguridad, ni archivos, …
Los file systems son transversales a cualquier tecnología de almacenamiento secundario: se necesita “formatear” en un file system, para poder guardar archivos.
Todo tiene file systems…
Un disco puede estar “raugh” “salvaje” o formateado. Salvaje es una tira de bits… formateado puede recibir archivos.
El FS es un elemento fundamental del sistema operativo y aporta las estructuras que permiten guardar archivos en el almacenamiento secundario.
El concepto de archivo no es físico, es lógico. Los dispositivos salvajes (raugh disk, o sea un disco sin formatear) son una tira de bits… con esto les damos estructura.
El concepto de archivo implica una unidad de manipulación de datos en el almacenamiento secundario.
No podemos guardar ½ archivo o 100grs de archivo… UN ARCHIVO ES UNA UNIDAD. Lo movemos, copiamos, generamos, etc como un TODO, como una unidad. Reside en MS.
Operaciones sobre archivos:
- Abrir
- Cerrar
- Crear
- Destruir
- Copiar
- Renombrar
- Listar
Operaciones sobre el contenido de los archivos:
- Los elementos de información individuales en un archivo se pueden manipular con operaciones como:
- Leer
- Escribir
- Modificar
- Eliminar
- Insertar
Características relevantes de los archivos:
- Volatilidad: Frecuencia de Escritura. Frecuencia con que se cambia la información de un archivo.
- Actividad: Frecuencia de lectura. Porcentaje de registros a los que se tuvo acceso en un período dado.
- Tamaño.
- Un componente fundamental en cualquier SO es el sistema de archivos o file system.
- Los FS contienen:
- Métodos de acceso: directorios, punteros a los datos en disco, etc.
- Administración de archivos: metadatos para ello, o sea: dueños, permisos, largo, etc.
- Administración de almacenamiento secundario: estructuras para guardar físicamente los datos.
- Mecanismos de integridad de los archivos: formas de comprobar si el contenido está corrupto. Paridad, CRC (código de redundancia cíclica), etc.
Tenemos los datos de un archivo, es decir su contenido, y los METADATOS: nombre, dueño, permisos, largo, etc.
- El FS se ocupa de administrar el espacio de almacenamiento secundario, sobre todo espacio en disco.
- Aquí aparecen los conceptos de:
- Cuenta: (conocido), conjunto de derechos sobre los recursos del sistema, que se abstraen a través de un nombre. Habrá, por comodidad, categorías de cuentas con derechos similares, por ejemplo los Admin.
- Dueño: el usuario dueño y el grupo dueño…
- Permisos: permisos para el propio dueño, para los integrantes del grupo dueño, para el resto del mundo…
- Estructura jerárquica del FS: directorios o carpetas. Los directorios no son una disposición física especial, sino lógica. Hay archivos con nombres especiales, que serán carpetas, y adentro tienen nombres de archivos o carpetas. Esto genera una estructura arborescente… Permite una organización lógica para ordenar.
- Un SO puede dar seguridad de archivos (y ser multiusuario) sólo si su FS lo permite.
Sobre el file system FAT, FAT32, etc, que no reconocen ni dueños ni permisos, no podemos crear o trabajar con sistemas operativos multiusuario, pues “todo es de todos” al no diferenciar en los metadatos dueños y permisos.
En Unix , Linux, Android, Windows con NTFS, obviamente, tenemos file systems que permiten el trabajo en modo multiusuario, al permitir dueños y permisos.
Funciones del file system:
- Se debe poder:
- Crear, modificar y eliminar archivos.
- Compartir archivos selectivamente.
- Al compartir, se deben ofrecer varios tipos de acceso controlados: lectura, escritura, etc.
- Agrupar los archivos en una estructura jerárquica.
- Transferir datos entre archivos.
- Respaldo y recuperación.
- Nombres simbólicos en sustitución de los físicos. Un archivo obviamente estará identificado por un número, pero mejor ocultar esto a los usuarios…
- Cifrado.
- Interfaz amable con el usuario, vista lógica adecuada.
Dejemos de hablar de los metadatos y hablemos del contenido de los archivos ahora.
Cómo se guardan los datos en disco ?
- Bloque o registro físico: unidad de lectura/escritura para un dispositivo. Por ejemplo un sector de un disco.
- Registro lógico: unidad de lectura/escritura para el usuario.
- Pueden relacionarse 1 a 1, n a 1 o 1 a n.
- El uso de buffers puede superponer cómputo y E/S.
Organización de archivos
- Refiere a la forma en que se acomodan los registros en un archivo en el almacenamiento secundario.
- Los métodos más comunes:
- Secuencial: Los registros se colocan en orden físico, uno a continuación del otro. OK para cintas (secuenciales).
- Directo: Se obtiene acceso directo a los registros por su dirección en el propio dispositivo. Típico en los discos.
- Secuencial indizado: Registros ordenados en forma lógica según un campo clave. Se manejan índices físicos y lógicos.
- De partición: organización en directorios.
- Se llama volumen al medio de grabación.
Como consecuencia del crecimiento dinámico de los archivos en los discos, obviamente los mismos no tendrán CONTIGUIDAD en el volumen… sino que estarán esparcidos por partes. Gracias a ello lograremos la posibilidad del crecimiento dinámico. A esto le llamamos fragmentación y es una consecuencia natural del crecimiento dinámico de los archivos.
- La fragmentación es un gran problema y degrada la performance del sistema. Recorrer archivos dispersos por todo el disco genera demoras, y demoras en acceso a disco. Degrada todo el sistema.
- Para evitarla se pueden realizar compactaciones y garbage collections, típicamente la desfragmentación del disco. En la medida que los sistemas apuntan en todo sentido a que el usuario se desentienda del mantenimiento, las mismas se automatizan.
- Algunos FS ya optimizan al mover/copiar (NTFS p/ej). Como tiene que recorrer todo el archivo sí o sí, ya aprovecha. En la copia del archivo. En la movida del archivo no es necesario recorrerlo, entonces es probable que no.
Técnicas de asignación
- Asignación contigua (sirve para cintas y otros secuenciales):
- Asignación contigua
- Los archivos se asignan a zonas contiguas del almacenamiento secundario.
- Se especifica por adelantado el tamaño del área requerida para guardar cierto archivo… y sólo se autoriza si hay espacio (esto se ve claramente no es muy flexible).
- Sólo crece el último archivo.
- Los directorios son fáciles de implementar, basta dar la dirección de inicio y la longitud del archivo.
- Desvantajas:
- Se generan huecos al asignar/borrar. Esto requiere condensaciones periódicas, etc.
- Cuando los archivos crecen dinámicamente, es inconveniente.
Sólo sirve para las cintas.
Recurrimos a técnicas de asignación no contigua.
- Asignación no contigua.
Contempla el problema del crecimiento dinámico de los archivos.
Varios tipos:
Asignación encadenada orientada a sectores:
Los sectores con datos de un mismo archivo se apuntan entre ellos.
Cuando un archivo necesita crecer, solicita más sectores. No hay necesidad de compactar.
Desventajas: Archivos disperdigados por todo el disco. Overhead alto por los punteros para el encadenamiento.
Los sectores son muy pequeños y es más conviente agrupar de a BLOQUES.
Asignación de bloques:
- Maneja de forma más eficiente el almacenamiento secundario.
- Reduce el overhead en tiempo y espacio.
- Es una mezcla de asignación contigua (bloques) y no contigua (el encadenamiento).
- Se asignan bloques de sectores contiguos.
- Al asignar bloques nuevos, se busca asignar los más cercanos físicamente. Cilindros vecinos.
- Una forma de implementarlo es el encadenamiento de bloques y el encadenamiento de bloques de índice (figura)
Encadenamiento de bloques:

En definitiva se corresponde con una lista encadenada de bloques contiguos.
Encadenamiento de bloques de índice:

La tabla de archivos con sus punteros se llama, en todos los casos FAT, FILE ALLOCATION TABLE (tabla de ubicación de archivos).
En los bloques de índice hay más overhead pero es un poco más rápido. Por estar menos disperdigado en el disco.
Mapa de archivos:
Este método evita el uso de grandes punteros.

Se ahorra todos los punteros! Se cambian por números de bloque, más fácil de manipular.
El file system resuelve todos los asuntos relacionados con el multiusuario.
Cómo controlamos el acceso y logramos el multiusuario?
- Para el control de acceso existen normalmente un conjunto de permisos, los que se habilitan o deshabilitan según los usuarios.
- Esto da lugar a una matriz de control de acceso. Para cada usuario y cada archivo, tendremos un conjunto de permisos.
- También aparecen diferentes roles y grupos de usuarios y categorías de archivos, para simplificar la administración.
- Aparece la figura del dueño de un archivo.
Algunos comandos Linux relacionados con esto:
Ls –l me muestra los metadatos completos de los archivos. Largo, permisos, dueños, etc.
Chmod permite cambiar los permisos de un archivo.
Cp copiar
Mv mover
Cd mkdir … carpetas
Rm borrar
Chown permite cambiar el dueño.
El file system provee algunas facilidades para los backups:
- El FS puede administrar ciertas redundancias, a nivel de sus estructuras (duplicando partes vitales por ejemplo), o a nivel del almacenamiento común. Esto permite respaldar las FAT de los file systems en el file system de cada una de las demás particiones.
- Hay un file system por partición.
- La partición es una división lógica del disco, de bajo nivel.
- Por ejemplo tenemos 3 particiones en un disco. Cada una tiene su FAT. Se copian las FAT de cada partición en las demás. Como forma de redundancia.
- Por ejemplo un archivo no puede crecer más allá de la partición que lo contiene.
- Con esto evitamos que los FS abiertos desborden a los FS del sistema.
- El SO puede dar mayor o menor soporte a los respaldos o dejarlo en manos de herramientas que corren sobre él.
- Puede haber respaldos completos o incrementales o combinación.
- Herramientas como tar y gz son de Unix/Linux desde las versiones iniciales dan soporte a los backups.
Ejemplo de respaldo completo:
Todos los días a las 3 am se copian los archivos vitales a cinta. Completos.
Si algo se daña, lo recuperamos del último backup disponible.
Ejemplo de respaldo incremental:
Todos los lunes a las 3 am sacamos respaldo completo.
Todos los demás días… martes… domingo, tomamos respaldos incrementales. (Sólo lo que cambió).
Supongamos algo se daña el viernes.
Restituimos backup completo del lunes..
Luego encima le pasamos la restitución del backup del martes.
Luego encima la del miércoles.
Luego encima la del jueves.
Y ahí restituyo el respaldo con lo último que tenía.
Esto respalda más rápido pero no me obliga a manejar más cintas.
Asuntos de cierre:
- El contenido del curso explota hacia tres áreas:
- SEGURIDAD INFORMÁTICA [ VER EN ESTE BLOG EL CURSO DE ATAQUES POR INGENIERÍA SOCIAL, ENTRE OTROS ASUNTOS DE ESTE PUNTO]
- SISTEMAS DE TIEMPO REAL
- GESTIÓN DE SISTEMAS [VER EN ESTE BLOG, EN LA PARTE DE ADMINISTRACIÓN DE INFRAESTRUCTURAS, EL CAPÍTULO INICIAL CON LOS ROLES DEL SYSADMIN Y EL GERENTE DE SISTEMAS].
.png)
No hay comentarios.:
Publicar un comentario
Nota: sólo los miembros de este blog pueden publicar comentarios.