Memoria y Sistemas de Archivos
Este material continúa el apunte de las dos primeras unidades. Aquí se estudian las dos grandes responsabilidades del sistema operativo que faltaban: cómo administra la memoria (un recurso escaso, rápido y volátil) y cómo organiza el almacenamiento permanente mediante archivos. Cada concepto se explica de forma progresiva y se acompaña de un laboratorio interactivo para experimentar con él. Donde suma rigor, el texto se amplía con la bibliografía de referencia: Tanenbaum (2009) y Stallings (2005).
Gestión de la Memoria
3.1 ¿Por qué la memoria necesita un administrador?
En un sistema monoprogramado la cuestión sería trivial: un único programa ocupa la memoria y listo. Pero los sistemas operativos modernos son multiprogramados: mantienen varios procesos cargados a la vez para que, mientras uno espera una operación de entrada/salida, el procesador pueda dedicarse a otro. Esa convivencia obliga a subdividir la memoria principal y a repartirla con criterio.
El objetivo de fondo es mantener el procesador ocupado. Si la memoria estuviera mal administrada, el CPU pasaría buena parte del tiempo ocioso esperando a que los procesos terminen sus operaciones de E/S. La gestión de memoria es, entonces, lo que hace viable la multiprogramación.
Los cinco requisitos de la gestión de memoria
Stallings (2005) sistematiza cinco requisitos que todo administrador de memoria debe satisfacer. Conviene revisarlos uno por uno, porque cada técnica que veremos más adelante existe para cumplir alguno de ellos. Las tarjetas se dan vuelta al hacer clic.
Regla mnemotécnica: Re-Pro-Com-Log-Fis — Reubicación, Protección, Compartición, organización Lógica y organización Física.
3.2 Particionamiento de la memoria
Las técnicas históricas más simples para repartir la memoria son el particionamiento fijo y el dinámico. Hoy casi no se usan —se prefieren la paginación y la segmentación—, pero entenderlas es clave porque introducen el problema central de toda gestión de memoria: la fragmentación. Un detalle importante: en el particionamiento un proceso solo puede ocupar una partición (la técnica de overlays permite cargar módulos adicionales para superar ese límite), y todo el esquema trabaja con direcciones relativas.
La memoria se divide de antemano en particiones de tamaño fijo, definidas al generar el sistema operativo. Pueden ser todas iguales o de tamaños variables.
Su talón de Aquiles es la fragmentación interna: si un proceso de 6 MB entra en una partición de 8 MB, esos 2 MB sobrantes quedan inutilizables dentro de la partición. Las particiones de tamaños variables reducen el problema, pero siguen limitadas en cantidad y tamaño.
Las particiones se crean a medida: cada proceso recibe exactamente el espacio que necesita. Esto elimina la fragmentación interna, pero introduce la fragmentación externa: al entrar y salir procesos quedan huecos libres dispersos, demasiado pequeños para reutilizarse.
La solución es la compactación —desplazar los procesos para juntar los huecos—, pero es muy costosa en tiempo de CPU.
Esta simulación representa una memoria de 64 unidades. Permite cargar procesos de distinto tamaño y observar dónde aparece el desperdicio. En modo fijo la memoria está cortada en bloques iguales de 16 unidades: cada proceso ocupa un bloque entero y lo que sobra es fragmentación interna (borde rojo interior). En modo dinámico cada proceso toma su tamaño exacto, pero al liberar procesos quedan huecos sueltos: esa es la fragmentación externa. Conviene probar a cargar y liberar varios procesos para ver cómo la memoria dinámica se "agujerea".
3.3 Algoritmos de ubicación
En el particionamiento dinámico, cuando llega un proceso hay que decidir en qué hueco libre colocarlo. Existen tres estrategias clásicas, y la elección no es inocente: cada una deja la memoria en un estado distinto y afecta la fragmentación futura.
- Primer ajuste (first-fit): recorre desde el principio y usa el primer hueco lo bastante grande. Es rápido porque corta apenas encuentra uno.
- Mejor ajuste (best-fit): busca el hueco cuyo tamaño sea el más cercano al pedido. Suena ideal, pero tiende a dejar fragmentos diminutos e inservibles.
- Siguiente ajuste (next-fit): como el primer ajuste, pero retoma la búsqueda desde la última posición asignada en lugar de volver al principio.
Sobre una memoria con varios huecos libres de distinto tamaño, esta herramienta muestra en qué hueco colocaría el proceso cada algoritmo. Hay que elegir el tamaño del proceso entrante y comparar la decisión de los tres: el hueco elegido se resalta. Es interesante notar cómo mejor ajuste suele meterse en el hueco más justo —dejando una astilla de espacio—, mientras que primer ajuste parte el primer hueco grande que encuentra.
3.4 El sistema buddy (de "compañeros")
El sistema buddy es un punto medio elegante entre el particionamiento fijo y el dinámico. La memoria se administra en bloques cuyo tamaño es siempre una potencia de dos. Cuando llega un pedido, se toma el bloque más chico que lo contenga; si es demasiado grande, se parte por la mitad repetidamente —generando pares de "compañeros" (buddies)— hasta llegar al tamaño justo. Al liberar memoria, si los dos compañeros quedan libres, se fusionan de nuevo. Esto hace que asignar y liberar sea muy rápido. Una versión modificada se usa para administrar la memoria del núcleo en UNIX.
Sobre un bloque inicial de 1024 KB, esta simulación muestra cómo el sistema buddy parte bloques a la mitad hasta satisfacer un pedido. Al solicitar memoria, observen cómo desciende dividiendo en potencias de dos hasta alcanzar el bloque más chico que alcance. Al liberar, los compañeros libres se recombinan automáticamente. Cada nivel del árbol es una potencia de dos.
3.5 Reubicación y los tres tipos de dirección
Un proceso no siempre vive en el mismo lugar de la memoria: el intercambio (swap) a disco y la compactación pueden moverlo. Por eso el sistema necesita un mecanismo de reubicación. Para entenderlo hay que distinguir tres tipos de dirección, que el hardware traduce en tiempo de ejecución:
Dirección lógica
Referencia independiente de la ubicación física actual del proceso. El programa la usa sin saber dónde está realmente cargado.
Dirección relativa
Una dirección lógica particular, expresada como desplazamiento desde un punto conocido (por ejemplo, el inicio del programa).
Dirección física (absoluta)
La ubicación real y concreta dentro de la memoria principal. Es la que viaja por el bus hacia la RAM.
La traducción de dirección lógica a física requiere soporte de hardware especial (un registro base que se suma a la dirección relativa, y un registro límite que verifica que no se salga de la partición). Gracias a esto, mover un proceso solo implica cambiar el registro base.
3.6 Paginación
La paginación es la versión mejorada del particionamiento fijo, y resuelve la fragmentación de raíz. La idea: dividir tanto la memoria como los procesos en unidades de tamaño fijo. A las porciones de la memoria física se las llama marcos (frames); a las porciones del proceso, páginas. Como cualquier página entra en cualquier marco, desaparece la fragmentación externa y la interna se reduce a, como mucho, una fracción de la última página.
Cada proceso tiene su tabla de páginas, que indica en qué marco está alojada cada una de sus páginas. El sistema operativo mantiene además una lista de marcos libres. La dirección lógica se parte en dos campos: un número de página y un desplazamiento dentro de ella. El hardware usa el número de página para buscar el marco en la tabla, y conserva el desplazamiento tal cual.
Este es el corazón de la paginación. Supongamos páginas de 4 KB (12 bits de desplazamiento) y un espacio de direcciones de 16 KB (4 páginas). Al ingresar una dirección virtual, la simulación la descompone en número de página + desplazamiento, busca el marco correspondiente en la tabla de páginas y arma la dirección física. Si la página no está cargada (bit presente/ausente en 0), se produce un fallo de página y hay que traerla del swap. Conviene probar direcciones de distintas páginas y observar cómo el desplazamiento nunca cambia: solo se reemplaza el número de página por el de marco.
3.7 Segmentación
Si la paginación mejora el particionamiento fijo, la segmentación mejora el dinámico. Aquí el programa se divide en segmentos de tamaño variable que responden a criterios lógicos: un segmento para el código, otro para la pila, otro para una tabla de datos. La dirección lógica lleva un número de segmento y un desplazamiento.
La gran diferencia con el particionamiento dinámico es que los segmentos no necesitan ser contiguos. La tabla de segmentos guarda, para cada uno, su dirección inicial (base) y su longitud (límite). Traducir implica: verificar que el desplazamiento no supere la longitud del segmento, y luego sumar la base. A diferencia de la paginación, la segmentación es visible para el programador, que puede aprovecharla para organizar el programa de forma modular.
| Aspecto | Paginación | Segmentación |
|---|---|---|
| Unidad | Tamaño fijo (página/marco) | Tamaño variable (segmento) |
| Criterio | Mecánico, transparente al programa | Lógico, visible al programador |
| Mejora a | Particionamiento fijo | Particionamiento dinámico |
| Fragmentación | Elimina la externa; interna mínima | Elimina la interna; mantiene externa |
| Traducción | nº página → marco (+ desplazamiento) | verificar límite + sumar base |
Ambos enfoques pueden combinarse (segmentación paginada) para tomar lo mejor de cada uno: la modularidad lógica de los segmentos y la ausencia de fragmentación externa de las páginas.
3.8 Memoria virtual (Fotheringham, 1961)
La memoria virtual da a cada programa su propio espacio de direcciones virtuales, dividido en páginas. La clave es que esas páginas no necesitan estar todas en la memoria física para poder ejecutar el programa. Solo se cargan las que hacen falta en cada momento; el resto vive en el área de swap del disco.
Cuando el programa accede a una dirección cuya página está en RAM, el hardware hace la traducción al instante. Pero si la página no está presente, se dispara un fallo de página: el sistema operativo recibe la alerta, busca la página faltante en el swap, la carga en un marco libre y reanuda la instrucción. Este mecanismo encaja perfecto con la multiprogramación: mientras un proceso espera que su página llegue del disco, el CPU se dedica a otro.
El componente de hardware que realiza la traducción es la MMU (Unidad de Administración de Memoria). El flujo de un acceso es el siguiente:
3.9 La tabla de páginas por dentro
Cada entrada de la tabla de páginas guarda mucho más que el número de marco. Estos campos son los que permiten que la memoria virtual funcione de forma segura y eficiente. Al hacer clic en cada bit se explica su rol.
| Campo | Para qué sirve |
|---|---|
| Número de marco | Indica en qué marco físico está la página. Es el dato que reemplaza al número de página virtual. |
| Presente / ausente | 1 = la página está en RAM. 0 = no está cargada → se produce un fallo de página. |
| Protección (rwx) | Qué accesos se permiten: lectura, escritura, ejecución. Es el mismo concepto de permisos visto en archivos. |
| Modificada (M) | Si la página fue escrita, está "sucia" y debe volcarse al disco antes de reemplazarla. Si no, está "limpia" y se descarta directo. |
| Referenciada (R) | Marca si la página se usó recientemente. Lo usan los algoritmos de reemplazo para decidir a quién echar. |
| Caché deshabilitado | Para páginas mapeadas a registros de dispositivos (E/S): no deben cachearse, hay que leer siempre el valor real. |
Estructuras que aceleran u optimizan la paginación
El búfer de traducción adelantada es un hardware tipo caché que guarda un puñado de asociaciones página→marco usadas recientemente. Si la dirección está en la TLB, la traducción es instantánea y no hace falta consultar la tabla de páginas en memoria.
En lugar de una tabla gigante, se organiza en varios niveles y solo se cargan en memoria las porciones que el proceso realmente usa. Ahorra memoria cuando el espacio de direcciones es enorme y disperso.
Guardan una entrada por marco físico (no por página virtual), ahorrando muchísimo espacio. El costo: para encontrar la página de un proceso hay que hacer una búsqueda por hashing sobre el par (proceso, página).
3.10 Algoritmos de reemplazo de páginas
Cuando ocurre un fallo de página y no hay marcos libres, el sistema operativo debe elegir una página que esté en memoria y desalojarla para hacer lugar. La pregunta del millón es cuál. Una mala elección puede provocar que la página recién expulsada se necesite enseguida (un fenómeno conocido como hiperpaginación o thrashing). Estos son los algoritmos clásicos, ordenados de ideal a práctico:
| Algoritmo | Cómo decide a quién echar |
|---|---|
| Óptimo | Expulsa la página que tardará más tiempo en volver a usarse. Es imbatible… pero requiere conocer el futuro, así que solo sirve como referencia teórica. |
| NRU | No usadas recientemente. Clasifica las páginas en 4 clases según sus bits R (referencia) y M (modificación), y desaloja una al azar de la clase más baja. Aproximación burda al LRU. |
| FIFO | Echa la página más antigua, sin mirar si todavía se usa. Simple, pero puede descartar páginas importantes. |
| Segunda oportunidad | FIFO mejorado: antes de echar la más vieja, si tiene su bit R en 1 le da otra oportunidad (pone R en 0 y la manda al final). Gran mejora sobre FIFO. |
| Reloj | La misma idea de segunda oportunidad, pero implementada con una lista circular y un puntero que avanza como la aguja de un reloj. Realista y eficiente. |
| LRU | Menos usada recientemente. Echa la que lleva más tiempo sin usarse. Excelente, pero implementarla con exactitud es caro. |
| NFU / Envejecimiento | NFU usa contadores que aproximan la frecuencia de uso (nunca "olvida"). El envejecimiento (aging) los reduce periódicamente para aproximarse mejor al LRU. |
| Conjunto de trabajo (Denning, 1970) | Mantiene en memoria el conjunto de páginas usadas recientemente. Reduce fallos pero es costoso. |
| WSClock (Carr y Hennessey, 1981) | Combina el reloj con el conjunto de trabajo. Rendimiento eficiente y práctico: el que se usa en la realidad. |
Esta es la pieza central de la unidad. Dada una cadena de referencias (la secuencia de páginas que pide el programa) y una cantidad de marcos disponibles, la simulación ejecuta el algoritmo elegido paso a paso. Cada columna es una referencia: arriba se ve la página pedida, abajo si fue acierto (verde, ya estaba en memoria) o fallo de página (rojo, hubo que traerla). Dentro de la grilla se ve el contenido de cada marco en ese instante; el borde verde marca la página recién cargada y el rojo la que fue expulsada. Al final se cuentan los fallos totales y la tasa de aciertos.
Dos experiencias muy reveladoras. Primera: con la cadena por defecto, comparar Óptimo (9 fallos, el piso teórico imbatible), LRU (12) y FIFO (15) con 3 marcos: se cumple siempre que Óptimo ≤ LRU ≤ FIFO. Segunda: cargar la cadena de Belady con el botón de abajo y ejecutar FIFO con 3 marcos (9 fallos) y luego con 4 marcos… los fallos suben a 10 en lugar de bajar. Eso es la anomalía de Belady: agregar memoria empeora el resultado, una de las razones por las que FIFO no se usa en la práctica.
Siete preguntas para repasar. La respuesta correcta se marca en verde al elegir.
Sistemas de Archivos
4.1 ¿Por qué existen los archivos?
La memoria principal tiene tres limitaciones fatales para guardar información a largo plazo: es pequeña (el tamaño del espacio de direcciones la acota), es volátil (al terminar el proceso, su información se pierde) y no permite que varios procesos compartan datos persistentes con facilidad. De ahí surgen tres requerimientos que todo sistema de almacenamiento permanente debe cumplir:
Mucha información
Capacidad de almacenar grandes volúmenes, muy por encima de lo que entra en la RAM.
Persistencia
La información debe sobrevivir a la terminación del proceso que la creó o la usa.
Acceso concurrente
Múltiples procesos deben poder acceder a la información de forma simultánea.
Un archivo es una unidad lógica de información creada por los procesos. En el fondo es un mecanismo de abstracción: oculta los detalles físicos del disco y ofrece una forma uniforme de guardar información y volver a recuperarla. Los procesos pueden leer archivos existentes y crear nuevos; el sistema operativo se encarga de administrarlos.
Para el usuario, lo importante de un archivo es su apariencia: cómo se llama, de qué se compone, cómo se protege y qué operaciones admite. Un par de detalles que suelen confundir: UNIX distingue mayúsculas y minúsculas en los nombres, MS-DOS no. Un archivo puede tener varias extensiones (pagina.html.zip), y esas extensiones son meras convenciones: indican algo sobre la naturaleza del archivo, pero el SO no las impone. Todo archivo lleva además atributos o metadatos: fecha de última modificación, tamaño, permisos, etc.
4.2 Cómo se estructuran los archivos
Hay tres maneras de organizar internamente un archivo, y la elección define cuánto "entiende" el SO de su contenido:
El archivo es un chorro de bytes sin estructura. El SO no sabe ni le importa qué contiene. Máxima flexibilidad. Es el modelo de UNIX, MS-DOS y Windows.
El archivo es una serie de registros de longitud fija. El usuario agrega o modifica registros completos. Modelo más rígido, propio de sistemas antiguos.
Registros con un campo llave ubicado en posición física conocida. Se ordena por esa llave para acelerar la búsqueda (como un árbol B).
Tipos de archivos
Windows maneja archivos y directorios regulares. UNIX agrega dos tipos especiales, fiel a su filosofía de "todo es un archivo":
| Tipo | Qué es |
|---|---|
| Regular | Contiene la información del usuario. Puede ser ASCII (se muestra e imprime tal cual) o binario. |
| Directorio | Archivo del sistema que mantiene la estructura del sistema de archivos. |
| Especial de caracteres | Modela dispositivos de E/S en serie (terminales, impresoras). |
| Especial de bloque | Modela los discos. |
Históricamente, las cintas magnéticas solo permitían acceso secuencial. Con la llegada de los discos duros apareció el acceso aleatorio: poder saltar directamente a cualquier registro mediante su llave, sin leer todo lo anterior.
4.3 Operaciones sobre archivos
El sistema operativo expone once operaciones básicas sobre archivos, accesibles mediante llamadas al sistema:
create
crea el archivo
delete
lo elimina
open
lo abre
close
lo cierra
read
lee datos
write
escribe datos
append
agrega al final
seek
reposiciona el puntero
get attributes
lee metadatos
set attributes
cambia metadatos
rename
lo renombra
4.4 Directorios y rutas
Hay dos formas de organizar los directorios. La primera —un único directorio que contiene todos los archivos— se usaba antiguamente y se vuelve inmanejable apenas hay muchos archivos. La que se impuso es la jerarquía de directorios: un directorio raíz del que cuelgan los directorios de cada usuario, sus subdirectorios y archivos, formando un árbol.
Para nombrar un archivo dentro del árbol hay dos clases de ruta. Las rutas absolutas parten siempre del directorio raíz y son únicas; el separador cambia según el sistema: UNIX usa /, Windows \ y MULTICS >. Las rutas relativas parten del directorio actual de trabajo. En ellas, . referencia el directorio actual y .. el directorio padre (salvo en la raíz, donde apunta a sí misma).
Este árbol de directorios funciona como un sistema de archivos en miniatura. Al hacer clic en cualquier archivo o carpeta, la herramienta muestra su ruta absoluta (desde la raíz /) y, además, cómo se vería su ruta relativa desde el directorio de trabajo actual, que se puede cambiar. Permite ver en acción los . y ..: por ejemplo, desde /home/ana el archivo /home/luis/cv.pdf se alcanza con ../luis/cv.pdf. Las carpetas se pueden plegar y desplegar.
4.5 Operaciones sobre directorios (UNIX)
UNIX define ocho operaciones de directorio. Dos merecen una nota: readdir devuelve la siguiente entrada de un directorio abierto, y link permite vincular un mismo archivo a más de un directorio (la base de los enlaces duros y de los archivos compartidos).
create
crea directorio
delete
lo elimina
opendir
lo abre
closedir
lo cierra
readdir
lee la siguiente entrada
rename
lo renombra
link
vincula un archivo
unlink
elimina un vínculo
4.6 Implementación de archivos: ¿cómo se guardan en el disco?
El disco se divide en particiones, cada una con su propio sistema de archivos. Al arrancar (o al montar la partición por primera vez) se lee el superbloque, que contiene los parámetros clave del sistema de archivos. La gran pregunta de diseño es: ¿cómo se lleva el registro de qué bloques del disco pertenecen a cada archivo? Hay cuatro estrategias clásicas, cada una con un balance distinto entre simplicidad, velocidad de acceso secuencial y velocidad de acceso aleatorio.
| Método | Idea, ventajas y desventajas |
|---|---|
| Asignación contigua | El archivo ocupa bloques consecutivos. Es simple (basta saber el primer bloque y la cantidad) y la lectura es excelente (todo de una). Pero el disco se fragmenta muy fácil y compactarlo es carísimo. Se usa en CD-ROM y DVD (tamaño fijo, nunca cambia). |
| Lista enlazada | Cada bloque apunta al siguiente. No hay fragmentación externa y la lectura secuencial es directa. Pero el acceso aleatorio es lentísimo (para llegar al bloque N hay que pasar por los N−1 anteriores) y el puntero roba unos bytes a cada bloque. |
| Lista enlazada con tabla en memoria (FAT) | Los punteros se sacan de los bloques y se ponen en una tabla en RAM. El acceso aleatorio se vuelve sencillo y los bloques quedan completos para datos. El problema: hay que mantener toda la tabla en memoria todo el tiempo, y su tamaño escala con el disco. |
| Nodos-i (inodos) | Cada archivo tiene una pequeña estructura con sus atributos y las direcciones de sus bloques. Solo necesita estar en memoria mientras el archivo está abierto, así que el consumo depende de la cantidad de archivos abiertos, no del tamaño del disco. Es el esquema de UNIX. |
Esta grilla representa un disco de 64 bloques. Al crear archivos de distinto tamaño, la simulación los aloja según el método elegido y los pinta con un color por archivo. En contigua verás que los archivos ocupan tramos seguidos —y que al borrar uno queda un hueco difícil de reaprovechar—. En enlazada y FAT los bloques de un mismo archivo pueden quedar dispersos (las flechas marcan el encadenamiento). Probá crear varios, borrar uno del medio y crear otro: con contigua aparece la fragmentación; con los demás, no.
4.7 El nodo-i por dentro
El inodo merece su propia sección porque es la estructura que sostiene a UNIX y Linux. La idea ingeniosa está en cómo maneja archivos grandes sin desperdiciar espacio en los chicos: guarda unas pocas direcciones directas a bloques, y reserva las últimas para direcciones indirectas, que apuntan a bloques que a su vez contienen más direcciones. Así, un archivo pequeño usa solo punteros directos, mientras que uno enorme se expande a través de la indirección. Hacé clic en cada parte del inodo.
El nodo-i
Asocia a cada archivo sus atributos y las direcciones de sus bloques de datos. Hacé clic en cada fila para ver su función. La clave del diseño es que el inodo solo necesita cargarse en memoria mientras el archivo está abierto.
Implementación de directorios
Un directorio es, internamente, una tabla que asocia nombres con la ubicación de los archivos. Hay dos enfoques:
Cada entrada tiene tamaño fijo y guarda directamente la dirección de disco y los atributos del archivo. Es el enfoque habitual en Windows.
Cada entrada referencia a un nodo-i, donde viven los atributos y direcciones. Es el enfoque habitual en UNIX, y es lo que permite los archivos compartidos.
Archivos compartidos: un mismo archivo puede aparecer en varios directorios. Se logra con una estructura dedicada: un inodo compartido (enlace duro) o un archivo de tipo LINK (enlace simbólico).
4.8 Sistemas de archivos avanzados
Con discos cada vez más lentos en comparación con CPU y RAM, las escrituras de trozos pequeños se volvieron un cuello de botella. De ahí surgieron diseños más sofisticados:
Acumula las escrituras pendientes en un búfer en memoria y, periódicamente, las junta en un único segmento contiguo que escribe al final del registro. Un hilo limpiador recorre el disco como un búfer circular, agregando segmentos nuevos al frente y removiendo los viejos del final.
Antes de modificar el sistema de archivos, anota en una bitácora qué va a hacer (acciones idempotentes). Si el sistema se cae, al reiniciar consulta la bitácora y completa el trabajo pendiente. Lo usan NTFS, ext3 y ReiserFS. Soporta transacciones atómicas (begin/end transaction).
Capa de abstracción que unifica distintos sistemas de archivos (NTFS, FAT32, exFAT…) bajo una interfaz común. UNIX integra todo en un solo árbol de directorios; Windows asigna una letra a cada unidad. POSIX es la interfaz superior del VFS (open, read, write, lseek…). El VFS no sabe ni dónde están los datos ni qué sistema subyace.
Por eso en Linux "no existen las unidades C: o D:": todos los discos se montan dentro del mismo árbol de directorios, y se accede a ellos por igual aunque tengan sistemas de archivos distintos.
4.9 Administración del espacio en disco
Casi todos los sistemas dividen los archivos en bloques de tamaño fijo que no necesitan ser adyacentes —mover un bloque suelto es más barato que reubicar el archivo entero—. La elección del tamaño de bloque es un compromiso clásico:
| Tamaño de bloque | Consecuencia |
|---|---|
| Grande | Buena lectura secuencial, pero los archivos pequeños desperdician espacio (fragmentación interna). |
| Pequeño | Aprovecha el espacio, pero encarece la lectura: hacen falta más búsquedas para leer un archivo. |
Registro de bloques libres
El sistema necesita saber qué bloques están libres. Hay dos métodos, y el laboratorio permite compararlos lado a lado:
Sobre un disco de 48 bloques, esta herramienta muestra los dos métodos de llevar el registro de bloques libres. El mapa de bits usa un bit por bloque (1 = ocupado, 0 = libre): compacto y fácil de escanear. La lista enlazada encadena los bloques libres entre sí. Al ocupar o liberar bloques al azar, observen cómo se actualiza cada representación. El mapa de bits requiere exactamente n bits para n bloques.
Mapa de bits
Lista enlazada de bloques libres
4.10 Cuotas y respaldos
Cuotas de disco
El administrador puede limitar cuántos archivos y bloques puede tener cada usuario. Se manejan dos umbrales: el límite suave, que se puede exceder temporalmente (con advertencias), y el límite duro, que no se puede sobrepasar bajo ninguna circunstancia.
Respaldos (backups)
Perder un sistema de archivos es peor que perder la computadora: el hardware se reemplaza, la información no. Por eso los respaldos son críticos. Algunas buenas prácticas: respaldar directorios específicos en lugar de todo el sistema, omitir los archivos que no cambiaron desde el último respaldo (respaldo incremental), y —según Tanenbaum— evitar comprimir los respaldos, porque un solo error en el medio puede arruinar todo el archivo comprimido. Hutchinson y colaboradores (1999) propusieron tomar instantáneas rápidas copiando estructuras críticas y aplicando copy-on-write a los cambios posteriores.
Hay dos estrategias para volcar (respaldar) un disco:
Copia desde el bloque 0 hasta el último, tal cual. Simple y rápido (a la velocidad del disco), pero copia bloques sin usar y cosas innecesarias. No puede restaurar archivos individuales ni hacer respaldos incrementales.
Parte de uno o más directorios y los vacía de forma recursiva, tomando solo lo modificado desde una fecha base. Más inteligente, pero más complejo. Consta de 4 fases.
El vaciado lógico no copia el árbol entero: ejecuta cuatro fases para respaldar solo lo necesario. Esta animación recorre el árbol marcando inodos. En verde, lo que se respalda; en gris, lo descartado. Avancen fase por fase para ver el razonamiento: primero marca todo lo modificado, luego poda las ramas sin cambios, y por último vuelca directorios y archivos en orden.
4.11 Consistencia del sistema de archivos
Una caída en medio de la escritura de un bloque puede dejar el sistema de archivos en un estado inconsistente. Para detectarlo y repararlo, UNIX tiene fsck y Windows tiene scandisk. La verificación trabaja en dos frentes: los bloques y los directorios.
Verificación de bloques
El programa arma dos tablas de contadores, una por bloque del disco. La primera cuenta cuántas veces aparece cada bloque en uso (referenciado por algún inodo); la segunda, cuántas veces aparece en la lista de bloques libres. La regla de oro: cada bloque debe aparecer exactamente una vez, en una sola de las dos tablas. Si aparece en ambas, o en ninguna, hay un problema.
Esta simulación muestra las dos tablas de contadores que arma fsck/scandisk para 12 bloques. En condiciones normales, cada bloque suma exactamente 1 entre las dos tablas. Al inyectar fallas se rompe esa invariante: un bloque perdido no aparece en ninguna tabla (se desperdicia), y un bloque duplicado aparece dos veces en uso (peligrosísimo: dos archivos creen ser dueños del mismo bloque). La herramienta detecta y señala cada anomalía.
Verificación de directorios
Se usa una tabla que cuenta, por archivo, en cuántos directorios aparece, y se compara con la cuenta de vínculos almacenada en su inodo. Dos errores posibles: si la cuenta del inodo es mayor que las entradas reales, el archivo queda "huérfano" y desperdicia espacio; si es menor, es peligroso, porque al borrar un enlace el archivo podría eliminarse aunque todavía esté referenciado en otro lado. La solución es ajustar las cuentas para que coincidan. fsck también detecta inodos inválidos, permisos riesgosos y archivos con bit SETUID sospechoso.
4.12 Rendimiento y desfragmentación
Varias técnicas mejoran el rendimiento del sistema de archivos. Bloques más grandes favorecen la lectura secuencial. Los sistemas con inodos pagan un costo —dos accesos, uno al inodo y otro al bloque—, que se mitiga colocando los inodos a la mitad del disco (reduce a la mitad la distancia de búsqueda) o dividiendo el disco en grupos de cilindros, cada uno con sus propios inodos y bloques libres (McKusick y col., 1984). También ayudan los cachés y la lectura adelantada.
Con el uso, crear y borrar archivos va dejando el disco fragmentado: archivos y huecos esparcidos por todas partes, lo que degrada el rendimiento. La desfragmentación reordena los archivos para hacerlos contiguos y juntar el espacio libre. En Windows se usa defrag. Algunos archivos no se mueven (paginación, hibernación, bitácora). Linux, con ext2/ext3, sufre mucha menos fragmentación gracias a cómo elige los bloques.
Este disco de 64 bloques está fragmentado: los bloques de cada archivo (mismo color) quedaron dispersos con huecos en el medio. Al ejecutar la desfragmentación, observen cómo los bloques se reagrupan por archivo y todo el espacio libre se consolida en una región contigua al final —exactamente lo que hace defrag—. La animación mueve un bloque por paso para que se vea el reacomodo.
4.13 Síntesis de la unidad
Visto desde afuera, un sistema de archivos es una colección de archivos y directorios con sus operaciones. Visto desde adentro, sus diseñadores deben resolver cómo asignar el almacenamiento y registrar qué bloque va con cuál archivo: contigua, lista enlazada, FAT o nodos-i. El espacio libre se administra con listas de bloques libres o mapas de bits. La confiabilidad mejora con vaciados incrementales y verificadores como fsck. El rendimiento mejora con cachés, lectura adelantada, colocación cuidadosa de bloques y sistemas estructurados por registro. Ejemplos reales: ISO 9660, MS-DOS y UNIX, que difieren en cómo registran los bloques, su estructura de directorios y la administración del espacio libre.
Ocho preguntas para repasar. La respuesta correcta se marca en verde al elegir.
Unidad 3 · Memoria Unidad 4 · Archivos
Apunte interactivo de Sistemas Operativos · Clases 7 a 11
Material elaborado sobre el resumen de cátedra y ampliado con la bibliografía de referencia.
Bibliografía: Tanenbaum, A. S. (2009). Sistemas operativos modernos (3.ª ed.). Pearson Educación.
Stallings, W. (2005). Sistemas operativos (5.ª ed.). Pearson Educación.