El sistema operativo: gestión de memoria El sistema operativo: gestión de memoria Índice de contenido El sistema operativo: gestión de memoria....................................................................................................1 Licencia......................................................................................................................................................1 Esquemas de carga de programas.............................................................................................................1 Enlazado.................................................................................................................................................1 Carga......................................................................................................................................................2 Estrategias de organización de la memoria...............................................................................................2 Partición fija...........................................................................................................................................3 Partición dinámica..................................................................................................................................3 Paginación..............................................................................................................................................4 Segmentación.........................................................................................................................................4 Segmentación y paginación....................................................................................................................5 Memoria virtual.........................................................................................................................................5 Concepto................................................................................................................................................5 TLBs.......................................................................................................................................................5 Políticas de lectura de páginas................................................................................................................6 Políticas de reemplazo............................................................................................................................6 Gestión del conjunto residente...............................................................................................................6 Hiperpaginación.....................................................................................................................................7 Licencia Este obra de Jesús Jiménez Herranz está bajo una licencia Creative Commons AtribuciónLicenciarIgual 3.0 España. Basada en una obra en oposcaib.wikispaces.com. Esquemas de carga de programas Generalmente, los programas se almacenan en forma de ficheros en algún medio de almacenamiento. A la hora de ejecutar un programa, es necesario leer este fichero y cargarlo en memoria para su ejecución. Este proceso implica una serie de transformaciones, y básicamente se compone de dos etapas: ● ● Enlazado: Consiste en determinar y reunir todos los módulos que componen un programa, como el programa en sí, las librerías que utiliza, etc. Carga: En el fichero, las direcciones de las diferentes variables, saltos, etc. se almacenan en forma relativa. Antes de ejecutar el programa, es necesario transformar estas direcciones a las direcciones reales que usará el programa una vez en ejecución. Enlazado Tipos de enlazado: ● ● ● Estático: En el momento de la compilación, se determinan los módulos necesarios para el programa, y se integran en el fichero ejecutable final. Dinámico: Igual que el estático, pero el proceso se lleva a cabo en el momento de la ejecución. Dinámico en tiempo de ejecución: En este caso, se carga la librería en memoria en la primera ocasión que se accede a ella. Además, se mantiene una única instancia de la librería en memoria, que usarán todos los programas que la necesiten. Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 1 El sistema operativo: gestión de memoria El enlazado estático tiene la ventaja de que genera ejecutables independientes del entorno, en el sentido de que no necesitan librerías externas. Ahora bien, el precio que se paga es un mayor tamaño de los ejecutables, y una duplicación de recursos si dos programas utilizan la misma librería (ambos la incluirían en su ejecutable). Por otra parte, si una vez compilado el programa aparece una nueva versión de la librería, los programas no la utilizarían. El enlazado dinámico sigue padeciendo el problema de la duplicación de datos en tiempo de ejecución, pero en este caso los ejecutables son más pequeños, y es posible actualizar las librerías en el sistema de manera que los cambios se propaguen a todos los programas que las usan. El enlazado dinámico en tiempo de ejecución presenta las ventajas del enlazado dinámico, pero además soluciona el problema de la duplicación de datos, al utilizar todos los programas una misma instancia de la librería. La desventaja que tiene es que, al estar la librería en un espacio de direcciones diferente al del resto del programa, se añade un nivel de indirección en cada acceso, lo que puede ralentizar la ejecución. En general, el esquema más utilizado es el dinámico en tiempo de ejecución, ya que el ahorro en uso de recursos respecto al dinámico y al estático compensan la disminución del rendimiento. El enlazado estático también tiene su uso en programas pequeños en los que se busque el máximo rendimiento o en los que sea importante la independencia respecto al sistema operativo y las librerías instaladas. Carga Como las direcciones almacenadas en un fichero ejecutable son relativas, en el momento de la carga del programa es necesario convertirlas a las direcciones reales de memoria. Existen diferentes esquemas: ● ● ● Carga absoluta: Al cargar, se convierten las direcciones relativas a direcciones absolutas de la zona de memoria en la que se va a cargar el programa. Impide reubicar el programa en otro momento. Carga reubicable: Establece las direcciones relativas respecto a 0, y dispone de un registro base que indica la dirección en la que se carga el programa. Durante la ejecución, se suma a la dirección relativa el contenido del registro base para determinar la dirección absoluta final. Permite reubicar el programa simplemente moviéndolo y cambiando el valor del registro base. Carga dinámica en ejecución: Dejar las direcciones en forma relativa, y en tiempo de ejecución resolver cada dirección. Es el esquema más flexible, pero el gran overhead añadido requiere hardware específico para que funcione bien. Generalmente, y dado que todos los sistemas operativos modernos utilizan memoria virtual, el esquema más utilizado es la carga dinámica en ejecución. En sistemas operativos empotrados también es posible encontrar esquemas reubicables. Estrategias de organización de la memoria En un sistema operativo multiprogramado, en el que a lo largo del tiempo van a ejecutarse diferentes programas, y donde por tanto entrarán y saldrán de memoria gran cantidad de procesos, es importante planificar la estrategia de organización de memoria. A continuación se muestran los principales esquemas. Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 2 El sistema operativo: gestión de memoria Partición fija En este caso, la memoria está dividida en bloques de tamaño fijo: De esta forma, a cada proceso se le asigna un bloque de la Tamaño fijo Tamaño variable memoria. Los bloques pueden ser todos del mismo tamaño 128 K 128 K 512 K (tamaño fijo) o tener diferentes tamaños (tamaño variable), si 256 K bien el tamaño de los bloques nunca cambia en tiempo de 512 K 512 K ejecución. El direccionamiento en este esquema es sencillo, basta con 512 K 512 K almacenar la dirección inicial del bloque en el que está el proceso, y sumarla a sus direcciones relativas en cada acceso. 512 K La reubicación también es sencilla, siempre y cuando existan 1024 K bloques disponibles del tamaño apropiado. 512 K Los problemas de este esquema son: ● ● Gran fragmentación interna: Es decir, se desperdicia espacio dentro de cada bloque si el proceso es de menor tamaño que el bloque. Este aspecto es aliviado en cierta manera por el esquema de tamaño variable, pero aún así sigue existiendo. Gran fragmentación externa: Se corresponde con el caso de que un proceso no se pueda cargar porque, a pesar de que globalmente hay suficiente memoria libre, no existe ningún bloque libre de su tamaño. Partición dinámica En este esquema, se utiliza una estrategia similar a la partición fija, pero los bloques se van creando y asignando según se necesitan. Por tanto, para cada proceso será necesario guardar dónde comienza su bloque y cuál es su longitud. P2 Al asignarse los bloques de forma personalizada a cada proceso, este esquema no padece de fragmentación interna. Ahora bien, sí que tiene fragmentación P3 externa debido a los huecos que van quedando a medida que los procesos entran y salen del sistema, lo que requiere compactar periódicamente el espacio de memoria. P4 Para intentar controlar esta fragmentación del espacio libre, es necesario planear bien cómo se asignan los espacios de memoria a los nuevos procesos. Básicamente existen tres esquemas: P1 ● ● ● ● First-fit: Se asigna el primer espacio libre de suficiente tamaño. Next-fit: Como first-fit, pero se empieza a buscar desde la última asignación, para no favorecer (y por tanto fragmentar) el comienzo de la memoria. Best-fit: Se asigna el espacio que mejor ajusta al tamaño del proceso. Worst-fit: Se asigna el espacio que peor se ajusta, es decir, el más grande disponible. Contrariamente a lo que pudiera parecer, el mejor algoritmo es worst-fit, seguido de first-fit, next-fit y, finalmente, best-fit. La explicación de que best-fit funcione tan mal es que, al buscar siempre el espacio que mejor ajusta, genera también huecos de espacio libre de pequeño tamaño, que son difíciles de asignar y, por tanto, generan fragmentación externa. Por ese mismo motivo, y al ser worst-fit el algoritmo que deja huecos de mayor tamaño, es el que genera menor fragmentación. Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 3 El sistema operativo: gestión de memoria Paginación Memoria 0 P1 0 1 1 2 2 7 1 P1.0 2 P1.1 3 4 P2.0 5 P2 6 0 4 7 1 9 8 9 P1.2 P2.1 Este esquema consiste en dividir, por una parte, la memoria en particiones de muy pequeño tamaño llamadas marcos, y, por otra, los programas en particiones del mismo tamaño que los marcos llamadas páginas. Para cada proceso, se guarda una tabla que asigna a cada página su marco correspondiente en memoria. El acceso a memoria consistiría en averiguar, a partir de la dirección de memoria, la página a la que se refiere la dirección. De esta manera se podría consultar la tabla de páginas para obtener el marco de memoria, y luego se le sumaría el desplazamiento para obtener la dirección final. El número de página correspondiente a una dirección serían simplemente los N bits más significativos de la misma, dependiendo N del tamaño de página. Por ejemplo, para un tamaño de página de 32 KB, los 12 bits menos significativos serían el desplazamiento, y el resto de bits indicarían la página. En un esquema paginado no existe fragmentación externa, y la fragmentación interna se reduce a la última página de un proceso, por lo que es despreciable. La principal desventaja es el overhead al acceder a memoria, puesto que para cada acceso hay que consultar la tabla de páginas del proceso. En cualquier caso, dadas las ventajas de este esquema, la mayoría de microprocesadores disponen de métodos hardware para acelerar la gestión de la tabla de páginas y poder usar un esquema paginado de forma eficiente. Segmentación Memoria 0 P1 0 Pos:0 Tam:1 1 Pos:1 Tam:2 2 Pos:7 Tam:1 P1.0 1 2 P1.1 3 4 5 P2 P2.0 6 0 Pos:4 Tam:3 7 1 Pos:8 Tam:2 8 P1.2 Es un esquema similar a la paginación, pero en el que los programas se dividen en segmentos en lugar de en páginas. La diferencia es que cada segmento puede tener un tamaño diferente, si bien el resto del funcionamiento es idéntico: una tabla de correspondencia entre segmentos y bloques de memoria, y un direccionamiento en el que parte de la dirección se usa para determinar el segmento y el resto para el desplazamiento. La segmentación no tiene fragmentación interna, aunque sí tiene fragmentación externa al ser los segmentos de diferente tamaño. P2.1 9 A pesar de la fragmentación, la ventaja de este sistema respecto a la paginación es que facilita la programación a alto nivel, favoreciendo la modularización del programa. De esta manera, es posible utilizar un segmento para código, otro para datos, etc., con lo que además de facilitar la escritura de programas se hace más fácil la protección de los mismos (p. ej. impidiendo escribir en segmentos de código). Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 4 El sistema operativo: gestión de memoria Segmentación y paginación Para combinar las ventajas de la segmentación y la paginación, es posible utilizar simultáneamente los dos esquemas. Así, la gestión de memoria sería paginada, es decir, dividiendo el programa en páginas y la memoria en marcos, pero además el programa se dividiría a más alto nivel en segmentos, cada uno de ellos con un tamaño en número de páginas. De esta manera, se pueden conseguir los beneficios en cuanto a modularidad de la segmentación, sin ninguno de sus inconvenientes, ya que al usar paginación no existiría fragmentación externa. En cualquier caso, la popularización de lenguajes de alto nivel, que por una parte permiten modularizar programas sin problemas, y que por otra alejan al programador de los detalles de implementación del sistema operativo, hacen que la segmentación no se utilice en exceso, ya sea por sí sola o combinada con paginación. Memoria virtual Concepto El esquema de memoria virtual consiste en establecer, para cada proceso, un espacio de direcciones virtual, e independiente del espacio de memoria real. En tiempo de ejecución, el sistema operativo se encargaría de mapear este espacio virtual a la memoria real. Una ventaja fundamental de este sistema es que permite tener cargada en memoria únicamente la parte de un programa que se está ejecutando, cargando las páginas a medida que se necesitan y descargándolas (por ejemplo a disco) cuando ya no se usan. Debido a los principios de localidad, en un momento dado sólo se utiliza una parte muy pequeña de la memoria que utilizará el programa en su ciclo de vida, por lo que el uso de memoria se reduce drásticamente, aumenta el grado de multiprogramación del sistema y, en particular, es posible ejecutar programas que requieren más memoria que la existente físicamente. El conjunto de páginas de un proceso que están cargadas en memoria en un momento dado es lo que se conoce como el conjunto residente del proceso. Este conjunto va variando con el tiempo a medida que se cargan y descargan páginas de memoria. Cuando el proceso intenta acceder a una página que no está en memoria, se produce un fallo de página, y el sistema operativo se encarga de cargar la página solicitada en memoria. Aunque generalmente la memoria virtual se utiliza en conjunción con la paginación, también es posible hacerlo en un esquema segmentado. TLBs A pesar de sus ventajas, el esquema de memoria virtual ralentiza notablemente el funcionamiento del sistema, ya que para cada acceso a memoria se requieren dos operaciones: una para traducir la dirección virtual a una dirección real, y otra con el acceso en sí. Para aliviar este problema, los microprocesadores modernos disponen de mecanismos hardware que facilitan el proceso. Un de las facilidades que incluyen los microprocesadores es el TLB (Translation Lookaside Buffer), que no es más que una pequeña caché muy rápida (generalmente asociativa) que contiene parte de la tabla de páginas del proceso. De esta manera, para la mayoría de accesos (el hit ratio suele ser superior al 99%) la CPU traduce las direcciones virtuales a direcciones físicas mediante el TLB, sin necesidad de accesos a memoria adicionales a la tabla de páginas. En caso de que la dirección virtual no esté en el TLB, la propia CPU se encarga de leerla de la tabla de páginas en memoria y actualizar el TLB. Si la página tampoco estuviese en la tabla de páginas, quiere decir que no está cargada en memoria, por lo que se generaría una interrupción, y el sistema operativo se encargaría de cargar la página en memoria. Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 5 El sistema operativo: gestión de memoria Políticas de lectura de páginas Las diferentes políticas de carga en memoria de páginas pueden ser principalmente dos: ● ● Por demanda: Cuando se produce un fallo de página, se lee la página de disco. Previa: Ante un fallo de página, se cargan en memoria la página que ha producido el fallo, así como las contiguas. Esto se basa en los principios de localidad y es especialmente eficiente en el inicio de los programas. Además, aprovecha también las características de los discos duros. Políticas de reemplazo En muchas ocasiones, la carga de una página en memoria implica la descarga de otra que ya estuviera allí. Escoger una buena política de reemplazo es fundamental para obtener un buen rendimiento del sistema, ya que las cargas de páginas son costosas en tiempo de ejecución. La opción ideal sería descargar de memoria la página a la que se va a tardar más tiempo en acceder, pero como eso es un dato imposible de obtener, existen diferentes esquemas que intentan aproximarse al ideal: ● ● ● FIFO: Se extrae siempre la página que lleva más tiempo en memoria. Poco preciso. LRU: Se mantiene un registro de accesos a cada página, y se descarga aquella que menos se ha usado recientemente. Es más eficiente que FIFO, pero es costoso de implementar. Política del reloj: Se basa en almacenar, para cada página, un bit que se activa al acceder a ella. A la hora de descargar páginas, se recorre de forma circular la lista de páginas hasta encontrar una página a 0. A medida que se recorre, se van poniendo los 1s a 0s, de modo que en el peor caso (todas las páginas están a 1) se volvería a la primera página. La eficiencia de este esquema es cercana a la de LRU, pero es mucho más sencillo de implementar. En cualquiera de estas políticas, si se descarga una página y en poco tiempo se vuelve a acceder, el sistema se resiente innecesariamente. Una forma de aliviar este problema es, al descargar una página, no borrarla de memoria sino simplemente quitarla de la tabla de páginas y guardar su referencia en una FIFO. Cuando realmente sea necesario liberar memoria, ir descargando las páginas de la FIFO, pero si la política de reemplazo se ha equivocado y se vuelve a acceder a una página supuestamente descargada, restaurarla será casi instantáneo. Para poder implementar este sistema, hay que iniciar las acciones de reemplazo antes de agotar completamente la memoria, de modo que se disponga de algo de margen. En realidad, este esquema es similar a una caché. Gestión del conjunto residente Para maximizar el número de procesos que pueden estar en memoria en un momento dado y, por tanto, el grado de multiprogramación del sistema, se suele limitar el número de páginas que puede tener simultáneamente en memoria un proceso, o lo que es lo mismo, su conjunto residente. Es importante establecer con precisión este tamaño, ya que un conjunto residente demasiado grande reduce el grado de multiprogramación del sistema, mientras que uno demasiado pequeño aumenta innecesariamente el número de fallos de página en el sistema. La gestión del conjunto residente también establece el alcance de la sustitución de páginas: puede ser local (se descargan páginas del proceso que ha provocado el fallo) o global (se consideran las páginas de todos los procesos). Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 6 El sistema operativo: gestión de memoria La asignación de tamaño del conjunto residente puede ser de dos tipos: ● ● Fija: Se asigna un número N fijo de páginas que puede tener en memoria un proceso, y este N se mantiene constante a lo largo de la ejecución del proceso. Implica alcance local. Variables: El valor de N va cambiando durante la vida del proceso según diferentes parámetros. En un esquema variable de asignación del conjunto residente, el valor de N fluctúa a lo largo de la ejecución del proceso. Idealmente, el valor de N debería ser aquel que produce un número de fallos de página mínimo. Las siguientes estrategias intentan acercarse a este ideal: ● ● ● Estrategia del conjunto de trabajo: Se monitoriza periódicamente a qué páginas accede el proceso, y se establecen estas páginas como su conjunto residente. Es un esquema difícil de implementar. Estrategia de frecuencia de fallos: Se establecen umbrales para la frecuencia de fallos provocados por el proceso en un intervalo concreto. Si se supera el umbral superior, se aumenta el tamaño del conjunto residente, mientras que si no se llega al umbral inferior, se reduce. Es fácil de implementar, pero tiene problemas en los transitorios (carga, reubicaciones del proceso, etc.). Estrategia de muestreo: Se funciona como en la estrategia de frecuencia de fallos, pero no se hace el recuento continuamente sino que sólo se hace cada cierto tiempo. Esto hace que sea menos sensible a los períodos transitorios. Hiperpaginación Cuando el tiempo dedicado por el sistema a los fallos de página supera al tiempo utilizado en la ejecución de los procesos, se dice que el sistema ha entrado en hiperpaginación. La causa de la hiperpaginación suele ser una excesiva multiprogramación, que provoca que el conjunto residente de todos los procesos sea insuficiente, y se disparen los fallos de página. Algunas soluciones a este fenómeno son: ● ● ● Utilizar una estrategia de gestión del conjunto residente, ya que estas estrategias no permiten lanzar un proceso hasta que no haya disponibles como mínimo tantas páginas de memoria como el tamaño de su conjunto residente. Ajustar el grado de multiprogramación del sistema según el tiempo entre fallos, aumentándolo o disminuyéndolo según evolucione. Suspender procesos hasta que la situación se estabilice. A la hora de escoger qué procesos suspender, se pueden utilizar diferentes criterios: prioridad, tamaño en memoria, número de fallos que ha provocado, etc. Jesús Jiménez Herranz, http://oposcaib.wikispaces.com 7