Métodos de Asignación El propósito de los métodos de asignación es el de estipular la cantidad de espacio para los archivos del disco, y q dicho espacio se utilice eficazmente y se pueda acceder a los ficheros con rapidez. Existen tres métodos de uso común para asignar el espacio en disco: → Asignación Contigua: este método requiere que cada archivo o fichero ocupe un conjunto de direcciones contiguas en el disco. Con esta ordenación, para moverse después al bloque b + 1 después del bloque b, no se requieren movimientos de la cabeza. Cuando es necesario mover la cabeza, solo hay que desplazarla una pista. De esta forma, el número de posicionamientos en disco para lograr el acceso a los archivos asignados contiguamente es el mínimo, al igual que el tiempo de posicionamiento. La asignación contigua de un archivo esta definida por la dirección en disco y la longitud del primer bloque. Si el archivo tiene una longitud de n bloques, comienza en la localidad b, entonces ocupa los bloques b, b + 1, b + 2…. La entrada del directorio para cada archivo indica la dirección del bloque inicial y la longitud del área asignada al archivo. El problema de este método consiste en encontrar espacio para un nuevo archivo. Una vez definida la implantación de la lista de espacio libre, se puede decidir como encontrar espacio para la asignación contigua de un archivo. Si el archivo que hay que crear tiene una longitud de n bloques, es necesario recorrer la lista de espacio libre hasta encontrar n bloques libres contiguos. Si se trata de un mapa de bits, es necesario encontrar n bits seguidos con valor 0; y en una lista de direcciones y recuentos, se requiere un recuento de por lo menos n. Otro problema que enfrenta este método es el de determinar cuanto espacio se necesita para el archivo. Al crear un archivo, hay que encontrar y asignar todo el espacio que necesitará, pero existe la dificultad de estimar con exactitud el tamaño final del archivo. Si se asigna poco espacio, el archivo no podrá extenderse, y mas aun y se usa la estrategia de asignación de mejor ajuste, ya que el espacio a ambos extremos del archivo puede estar ocupado. En este caso es imposible hacer más grande el archivo, por lo que surgen dos posibilidades: la primera consiste en abortar el programa del usuario y la segunda consiste en encontrar un hueco más grande, copiar el contenido del archivo al nuevo espacio y liberar el anterior. Esta última solución es posible siempre que quede espacio suficiente y consume una cantidad de tiempo considerable. → Asignación Enlazada: Este método resuelve los problemas que presenta la asignación contigua, pues cada archivo es una lista enlazada de bloques de disco que pueden encontrarse en cualquier parte del mismo. El directorio contiene un apuntador al primer y ultimo bloques del archivo. En un principio se asigna un valor nulo para representar un archivo vacío. Una escritura al archivo quita el primer bloque disponible de la lista de espacio libre y escribe en el; luego se enlaza el nuevo bloque al final del archivo. Para leer un archivo, basta con leer los bloques siguiendo los apuntadores. Con este tipo de asignación no hay fragmentación externa ya que todos los bloques están enlazados y por lo tanto cualquiera de la lista de espacio libre puede usarse para satisfacer una solicitud. Tampoco es necesario declarar el tamaño del archivo durante su creación. El archivo puede continuar su crecimiento mientras queden bloques libres. No obstante, la asignación enlazada tiene sus desventajas. El mayor problema es que solo puede aplicarse eficazmente con archivos de acceso secuencial, ya que para encontrar el bloque i de un archivo hay que comenzar en el principio del archivo y seguir los apuntadores hasta llegar al bloque deseado, además que, cada acceso a un apuntador requiere de una lectura del disco. Otra desventaja es el espacio requerido por los apuntadores, por lo que cada archivo requerirá un poco más de espacio, que además no será utilizado para albergar más información. Otra dificultad es la poca confiabilidad que presenta, ya que los archivos, al estar dispersos por todo el disco, están expuestos a perderse si tan solo se daña o pierde un apuntador. Un error común es la elección de un apuntador incorrecto, enlazando el archivo a otro. Una solución a este inconveniente consiste en el empleo de listas doblemente enlazadas, o almacenar en cada bloque el nombre del archivo y el número del bloque, aunque estos esquemas requieren mas espacio para cada archivo. → Asignación Indizada: este método busca resolver los problemas de los anteriores reuniendo todos los apuntadores en un solo lugar, llamado Bloque de Índices. Cada archivo tiene su propio Bloque de Índices, el cual es un arreglo de direcciones de bloque en el disco. La entrada i en el bloque de índices apunta al bloque i del archivo. El directorio contiene la dirección del bloque de índices. Para leer el bloque i se utiliza el apuntador de la entrada i del bloque de índices para localizar y leer el bloque deseado. Al crear un nuevo archivo, se asigna a nulo todos los apuntadores del Bloque de Índices. Cuando el bloque i se escribe por primera vez se saca un bloque de la lista de espacio libre y se coloca su dirección en la entrada i del Bloque de Índices. La dificultad de este método es el desperdicio de espacio, ya que generalmente es mayor el espacio adicional requerido para los apuntadores del Bloque de Índices que para una asignación enlazada. Otra dificultad es el tamaño del Bloque de Índices. Cada archivo debe tener un Bloque de Índices cuyo tamaño ideal seria el menor posible. Sin embargo, si es demasiado pequeño no podrá almacenar todos los apuntadores para un archivo grande, por lo que es necesario un mecanismo para tratar esta situación. Velocidad del Disco La velocidad del disco se compone de tres elementos: para acceder a un bloque en el disco, el sistema primero debe mover la cabeza a la pista o cilindro correspondiente. A este movimiento se le denomina posicionamiento, y al tiempo para concluirlo se le conoce como tiempo de posicionamiento. Una vez que la cabeza se encuentra en la pista correcta debe esperar a que el bloque deseado pase por debajo de la cabeza de L / E, a esta demora se le denomina tiempo de latencia. Por ultimo puede efectuarse la transferencia real de datos entre el disco y la memoria principal, esta última parte es el tiempo de transferencia. El Tiempo Total para servir una solicitud del disco es la suma de los tiempos de posicionamiento, latencia y transferencia. Métodos de Planificación del Disco Planificación FCFS (First Come – First Served; Servicio por Orden de Llegada): es el algoritmo más sencillo, pero probablemente no ofrece el mejor tiempo de servicio. Ejemplo: Considere una cola de disco con las solicitudes en el siguiente orden: 98, 183, 37, 122, 14, 124, 65, 67 En al grafico contiguo se evidencia el violento movimiento de la 122 a la 14 y de vuelta a la 124. Lo ideal seria poder servir juntas todas las solicitudes para reducir considerablemente el movimiento total de la cabeza y también el tiempo para servir cada solicitud, mejorando la productividad del disco. Planificación SSTF (Shortest Seek Time First; Primero la Solicitud con el Tiempo de Búsqueda o Posicionamiento Menor): Parece razonable servir juntas todas las solicitudes próximas a la posición actual del disco, antes de desplazar la cabeza a un punto lejano para servir otra solicitud. Este algoritmo selecciona la solicitud con el menor tiempo de posicionamiento a partir de la posición actual de la cabeza. Este tipo de planificación es una variación de la Planificación SJF y como tal puede causar el bloqueo indefinido de algunas solicitudes. Suponga que se tienen 2 solicitudes en la cola, una para la 14 y otra para la 186. Si llega una solicitud próxima a la 14 mientras se sirve esta solicitud, será la siguiente solicitud en atenderse, por lo que la solicitud de la 186 tendría que esperar. Mientras se sirve la nueva solicitud, puede llegar otra próxima a la 14. En teoría, podría llegar una serie continua de solicitudes próximas entre sí, ocasionando que la solicitud de la pista 186 espere indefinidamente. Ejemplo: el mismo que el anterior. En el grafico contiguo se evidencia la mejora considerable en el promedio del servicio del disco, ya que da como resultado un movimiento total de la cabeza de 236 pistas. Planificación SCAN: Este algoritmo surge de la naturaleza dinámica de la cola de solicitudes. La cabeza de L / E comienza en un extremo del disco y se desplaza hacia el otro, sirviendo las solicitudes al llegar a cada pista, hasta alcanzar el extremo opuesto. Al llegar a este extremo, se invierte la dirección del movimiento de la cabeza y continúa el servicio, rastreando continuamente el disco de un extremo a otro. Ejemplo: el mismo que el anterior. Antes de aplicar el algoritmo es necesario conocer la dirección del movimiento de la cabeza, así como su posición mas reciente. Si se movía hacia la 0, el movimiento de la cabeza atendería las solicitudes 37 y 14. Al llegar a la pista 0, se invertiría el movimiento de la cabeza y se desplazaría hacia el extremo opuesto, sirviendo las solicitudes 65, 67, 98, 122, 124 y 186 durante el movimiento. Es importante mencionar que si una solicitud llega justo delante de la cabeza, se servirá casi de inmediato, mientras que una solicitud correspondiente a una posición inmediatamente detrás de la cabeza tendrá que esperar a que la cabeza se mueva hasta el final del disco, invierta su dirección de movimiento y regrese antes de ser servida. Planificación C – SCAN: Es una variante de la planificación SCAN, diseñada para ofrecer un tiempo de espera más uniforme. Al igual que el método anterior, C – SCAN mueve la cabeza de un extremo del disco a otro, sirviendo las solicitudes durante su marcha; sin embargo cuando llega al extremo opuesto regresa de inmediato al inicio del disco, sin servir ninguna solicitud en el camino. Planificación LOOK Los dos métodos anteriores siempre mueven la cabeza de un extremo del disco al otro. En la práctica ninguno se implanta de esta forma, sino que es más común que la cabeza se mueva hasta la última solicitud en cada dirección. Si ya no existen solicitudes en la dirección actual, se invierte el movimiento. A estas versiones de los algoritmos SCAN y C – SCAN se les llama planificación LOOK y C – LOOK (que significa mirar, ya que “mira” si hay una solicitud antes de moverse en esa dirección. Grafico correspondiente a la Planificación C - SCAN Grafico correspondiente a la Planificación C - LOOK ADMINISTRACIÓN DE MEMORIA El propósito principal de un sistema de computación es ejecutar programas, los cuales, junto con los datos que utilizan, deben encontrarse (por lo menos en parte) en la memoria principal. Anteriormente se pudo ver como un conjunto de procesos puede compartir la UCP. Como resultado de la panificación de la UCP se puede mejorar tanto su uso como su velocidad de respuesta a los usuarios. Sin embargo, para lograr este incremento en el rendimiento, es necesario conservar varios procesos en memoria, es decir, compartir la memoria. A continuación se analizar las distintas estrategias existentes para administrar la memoria, las cuales, presentan un único requisito: todo el programa debe encontrarse en la memoria física antes de ejecutarse. Esto, limita el tamaño máximo del proceso al tamaño de la memoria física. Enlace de Direcciones Para ejecutar un proceso, este debe cargarse en memoria. Generalmente el proceso reside en disco como un archivo binario ejecutable. El conjunto de procesos en disco que esperan entrar en la memoria para ejecutarse integran la Cola de Entrada. El procedimiento normal consiste en seleccionar uno de los procesos de la Cola de Entrada y cargarlo en memoria. Esta técnica ocasiona la relocalización de direcciones. Mientras se ejecuta el programa, accede a las instrucciones y datos en memoria. Finalmente el programa termina y su espacio en memoria se declara disponible. En la mayoría de los casos un programa de usuario pasará por varias etapas antes de ejecutarse. En estas etapas las direcciones pueden representarse de distintas maneras. En un programa fuente las direcciones son generalmente simbólicas. Un compilador enlazara estas direcciones simbólicas con direcciones relocalizables. A su vez el editor de enlaces o cargador enlazará estas direcciones relocalizables con direcciones absolutas. Cada enlace es una correspondencia entre un espacio de direcciones y otro. Superposiciones Puesto que todo el espacio lógico de direcciones de un proceso debe encontrarse en la memoria física antes de ejecutar el proceso, la dimensión de un proceso esta limitada por el tamaño de la memoria física. Para que un proceso pueda ser mayor que la cantidad de memoria que se le asigna, en ocasiones se utiliza una técnica llamada superposiciones; la idea es conservar en memoria solo aquellas instrucciones y datos que se requieran en un momento dado. Cuando se necesitan otras instrucciones, se cargan en el espacio que antes ocupaban las que ya no se requieren. Ejemplo: considere un ensamblador de 2 pasos. Durante el paso 1 construye una tabla de símbolos; luego durante el paso 2, genera el código del paso 1, código del paso 2, tabla de símbolos y rutinas de apoyo comunes utilizadas en los pasos 1 y 2. suponga que los tamaños de estos componentes son los siguientes: Paso 1 Paso 2 Tabla de Símbolos Rutinas Comunes 70 K 80 K 20 K 30 K 200 K Para cargar todo a la vez necesitaríamos 200 K de memoria; si solo hay 150 K disponibles, no podemos ejecutar nuestro proceso. Sin embargo observe que el paso 1 y el paso 2 no necesitan estar en memoria al mismo tiempo, de modo que: definimos dos superposiciones: A. la tabla de símbolos, las rutinas comunes, y el paso 1 = 120 K B. la tabla de símbolos, las rutinas comunes, y el paso 2 = 130 K agregamos un manejador de la superposición (10 K) y comenzamos con la superposición A en memoria. Cuando terminamos el paso 1 pasamos al manejador de la superposición, que lee la superposición B en memoria, sobrescribiendo la A, y luego se transfiere el control al paso 2. la superposición A solo necesita 120 k mientras que la superposición B solo necesita 130. de esta forma es posible ejecutar el ensamblador en los 150 K de memoria disponible. Intercambios Un proceso necesita estar en memoria para ejecutarse. Sin embargo, este puede intercambiarse temporalmente saliendo de la memoria a un almacenamiento secundario, y regresando luego a la memoria para continuar su ejecución. Por ejemplo, suponga un entorno de multiprogramación con un algoritmo de planificación circular o Round – Robin de la UCP. Cuando un cuanto expira, el administrador de la memoria comenzará a intercambiar el proceso que acaba de terminar, para incorporar otro proceso al espacio de memoria que acaba de liberarse. Mientras tanto, el planificador de la UCP asignará una porción de tiempo a otro proceso en memoria. Normalmente, un proceso que sale de un intercambio regresará al mismo espacio de memoria que antes ocupaba. Los intercambios requieren de almacenamiento auxiliar, el cual generalmente es un disco. El sistema mantiene una cola de procesos listos que consiste en todos los procesos cuya imagen de memoria se encuentra en el almacenamiento auxiliar o en memoria y están listos para ejecutarse. Cuando el planificador de la UCP decide ejecutar un proceso, llama al despachador, el cual comprueba si el siguiente proceso de la cola esta en memoria. Si no esta, y no se cuenta con una región de memoria libre, el despachador intercambia un proceso en memoria con el proceso deseado. Obviamente el tiempo de cambio de contexto en un sistema de intercambios es bastante alto. También vale mencionar, que la mayor parte del tiempo que se invierte en el intercambio se invierte en la transferencia. El tiempo total de transferencia total es directamente proporcional a la cantidad de memoria que se intercambia, por lo que resultaría útil saber exactamente cuanta memoria usa un proceso de usuario realmente, para intercambiar solo lo que realmente se esta usando y en consecuencia reducir el tiempo de transferencia. Asignación de Particiones Múltiples El problema de la administración de memoria consiste en asignar memoria a los distintos procesos que esperan en la cola de entrada para ser transferidos a memoria. Uno de los esquemas mas sencillos para la asignación de memoria consiste en dividirla en varias particiones de tamaño fijo. Cada partición puede contener exactamente un proceso. De esta forma el nivel de multiprogramación esta dado por el numero de particiones. Cuando una partición esta libre, se selecciona un proceso de la cola de entrada y se carga en la partición libre; cuando el proceso termina, la partición esta disponible para otro. Esquema Básico El S.O. conserva una tabla que indica que partes de la memoria están disponibles y cuales no lo están. Inicialmente toda la memoria esta disponible para los procesos de usuario y se considera como un gran bloque de memoria disponible, o un hueco. Cuando llega un proceso y necesita memoria, se busca un hueco de tamaño suficiente para ese proceso. Si se encuentra, se asigna solo la cantidad de memoria necesaria, quedando disponible el resto para satisfacer solicitudes posteriores. Ejemplo: se tiene 2560 k de memoria disponible, y un S.O. residente de 400 K. esta situación deja 2160 K para los procesos de usuario. Para asignar el espacio de memoria a los diferentes procesos, se toma en consideración lo siguiente: S. O. 0 a) Se utiliza la planificación FCFS, con lo que 400 k se asigna de inmediato los procesos P1, P2 y P3. queda un hueco de 260 K que no puede ser asignado a los procesos restantes. 2160 K b) Utilizando la planificación circular con 256O K un cuanto de 1 m/s, el proceso P2 termina en el instante 14 liberando su asignación de memoria c) Se regresa a la cola y se inicia con el siguiente proceso que es P4 d) El proceso P1 termina en el instante 28 e) Se inicia la ejecución del proceso P5 S. O. 400 K S. O. 400 K P1 P1 1000 K 400 K 1000 K S. O. 400 K S. O. 400 K P5 P1 1000 K S. O. 900 K 1000 K 1000 K P2 P4 1700 K 2000 K 2300 K P3 2560 K 2000 K 2300 K P3 2560 K a) 2000 K 1700 K P3 2300 K 2000 K P3 2000 K P3 2300 K 2560 K c) P4 1700 K 2300 K 2560 K b) P4 2560 K d) e) Este ejemplo ilustra varios puntos. En general en cualquier momento, hay un conjunto de huecos de distintos tamaños y dispersos por toda la memoria. Cuando llega un proceso y necesita memoria, se busca en este conjunto un hueco con el tamaño suficiente para el proceso. Si el hueco es demasiado grande, se divide en dos: una parte se asigna al proceso que llega y la otra se devuelve al conjunto de huecos. Cuando termina un proceso, libera su bloque de memoria, el cual se coloca de nuevo junto al conjunto de huecos. Si el nuevo hueco es adyacente a otros, los fusionamos formando uno mayor. Al llegar a este punto, es necesario comprobar si hay procesos esperando memoria y si esta nueva memoria liberada y recombinada puede satisfacer las solicitudes de algunos de estos procesos. Se trata entonces, de satisfacer una solicitud de tamaño n a partir de una lista de huecos libres. Para ellos se emplean las siguientes estrategias para seleccionar un hueco libre de un conjunto de huecos disponibles: 1. Primer ajuste: asigna el primer hueco que tenga el tamaño suficiente. La búsqueda puede comenzar en el inicio del conjunto de huecos o a partir de donde terminó la búsqueda anterior. Se dejan de buscar en el momento en el que se haya un hueco libre de suficiente tamaño. 2. Mejor ajuste: se asigna el hueco más pequeño que tenga el tamaño suficiente. Se debe recorrer toda la lista a menos que se tenga ordenada por tamaño. Esta estrategia produce el hueco sobrante más pequeño. 3. Peor ajuste: asigna el hueco más grande: una vez más, se debe buscar en toda la lista, a menos que se encuentre ordenada por tamaño. Esta estrategia produce el hueco sobrante más grande. Estas estrategias padecen de dos inconvenientes conocidos como Fragmentación Externa y Fragmentación Interna. La primera se da cuando el espacio de memoria es suficiente para atender una solicitud, pero no es contiguo, por lo que el almacenamiento esta fragmentado en varios huecos pequeños; es decir, conforme los procesos se cargan y extraen de la memoria, el espacio libre que queda se divide o descompone en pequeños pedazos. El principal problema que se produce con este tipo de fragmentación ocurre cuando hay suficiente espacio de memoria para atender una solicitud, pero este se encuentra fragmentado en pequeños huecos. La segunda ocurre cuando cierta parte de memoria pertenece a una partición, pero no se utiliza. Un ejemplo de esta situación es el siguiente: considere que existe un hueco de 18464 bytes y un proceso de 18462 bytes. Si se asigna el proceso a este hueco, se produce un hueco de 2 bytes, además del procesamiento para administrar dicho hueco, que será considerable en relación al tamaño del hueco sobrante. Planificación a Largo Plazo A medida que entran procesos en el sistema, se van colocando en una cola de entrada. El Planificador a Largo Plazo (PLP) tiene en cuenta los requisitos de memoria de cada proceso y la cantidad de memoria disponible para determinar a que procesos se les asigna. Cuando a un programa se le asigna espacio, se carga en memoria. Entonces puede competir por la UCP. Cuando termina un proceso, libera su memoria, y el planificador de la UCP puede llenarla con otro proceso de la cola de entrada. En cualquier momento se tiene una lista de tamaños de bloques disponibles y la cola de entrada. El PLP puede ordenar la cola de entrada de acuerdo con algún algoritmo de planificación. La memoria se asigna a los procesos hasta que finalmente no puedan satisfacerse los requisitos de memoria del siguiente proceso; no hay ningún bloque de memoria o hueco de suficiente tamaño para contener el proceso. Entonces el PLP puede esperar hasta que este disponible un bloque de tamaño suficiente o recorrer la cola de entrada para ver si pueden satisfacerse las solicitudes de menor cantidad de memoria de algún proceso de menor prioridad Compactación Representa una solución para la Fragmentación Externa. El objetivo consiste en desplazar el contenido de la memoria para colocar junta toda la memoria libre en un solo bloque de gran tamaño. El esquema mas sencillo para implementar la Compactación es el de mover todos los procesos hacia un extremo de la memoria; moviendo de esta forma todos los huecos en la dirección contraria, produciendo un gran hueco de memoria disponible. Es importante mencionar que no siempre es posible realizar la compactación.