Está en la página 1de 23

Acuña, Avila, Manzano, Martinez, Segovia

1
_________________________________________________________________________

CONTENIDO

_________________________________________________________________________

Acuña, Avila, Manzano, Martinez, Segovia


2
2.1 Conceptos Fundamentales
Administración de memoria:
El modelo de memoria de Linux es simple, para que los programas sean portátiles y se
pueda implementar Linux en máquinas con unidades de administración de memoria que
tengan amplias diferencias, desde casi nada (por ejemplo, la IBM PC original) hasta el
hardware de paginación sofisticado. Ésta es un área del diseño que ha cambiado muy poco
en décadas. Ha funcionado bien, por lo que no ha necesitado mucha revisión. Ahora
examinaremos el modelo y la forma en que se implementa.
Memoria Virtual
Para empezar, los sistemas Linux utilizan un modelo de memoria virtual para el manejo de
la memoria de los procesos y del sistema. De forma muy resumida un modelo de memoria
virtual consiste en la definición de un espacio de memoria “virtual” para cada proceso, dicho
espacio cuenta con sus propias direcciones de memoria virtual las cuales, al ser accedidas,
se las traduce a direcciones de la memoria física creando así una relación entre la memoria
virtual y la memoria física, permitiendo la ejecución de programas cuyos requerimientos de
memoria superen el tamaño de la memoria principal del CPU.
Luego, la memoria virtual se divide en “páginas” y la memoria física se divide en “marcos”
siendo ambos bloques de memoria del mismo tamaño. Cuando una instrucción ejecutada
en CPU requiere datos contenidos en un página ubicada en memoria virtual, a esta página
se le asigna un marco y es cargada en la sección de memoria física de dicho marco. Este
mecanismo se conoce como paginación por demanda. Es importante indicar que un marco
puede tener asignadas varias páginas de distintos procesos, siempre y cuando estas
páginas sean idénticas.
Una explicación más detallada acerca del proceso para el manejo de marcos y páginas,
conocido como paginación, se dará en la sección de implementación y la de paginación de
este informe.
Estructura de los espacios de memoria
Como se mencionó en la unidad de procesos, cuando se inicializa un proceso en
Linux se le define un espacio de memoria (en el caso de Linux es un espacio de memoria
virtual) el cual contiene todos los datos necesarios para la ejecución del proceso. Para
administrar estos datos, los espacios de memoria que los contienen están divididos en tres
segmentos lógicos conocidos como texto, datos y pila.

Acuña, Avila, Manzano, Martinez, Segovia


3
Fig 1. Segmentos del espacio de memoria de un proceso.

Como es evidente este segmento de la memoria de un proceso no se puede modificar. Sin

embargo, estos segmentos se pueden compartir gracias a la forma en la se manejan los

marcos dentro de la memoria virtual. El poder cargar solo una vez en memoria física un

mismo segmento de memoria para varios procesos soluciona los posibles problemas que

generaría el ejecutar varios procesos que tengan el mismo conjunto de instrucciones.

El segmento de datos, que según Tanenbaum (2009), “contiene almacenamiento para

todas las variables del programa, cadenas, arreglos y demás datos” está conformado por

tres secciones principales. La primera sección es descrita por Tolomei de la siguiente

manera: “esta porción del espacio de direcciones virtuales de un programa contiene las

variables globales y estáticas inicializadas por el programador”. La segunda sección,

llamada BSS (Block Started by Symbol) por una referencia histórica, contiene el resto de

variables globales y estáticas que no son inicializadas por el programador. Como

consecuencia de esto y de la forma en la que el lenguaje C maneja las variables no

inicializadas, Linux implementa optimizaciones para evitar el uso ineficiente de la memoria

física.

Acuña, Avila, Manzano, Martinez, Segovia


4
La última sección, llamada montículo, según Tolomei contiene “variables cuyo tamaño sólo

puede conocerse en tiempo de ejecución y no puede ser determinado estáticamente por el

compilador antes de la ejecución del programa”. El mecanismo de asignación de memoria

“extra” durante la ejecución de un proceso se conoce como asignación dinámica de

memoria y generalmente es controlado por las funciones malloc/new y free/delete del

lenguaje C y las llamadas al sistema brk y sbrk de Linux.

La sección del montículo dentro del segmento de datos y el segmento de pila, conocidos

también como heap y stack respectivamente, cumplen una función similar: contener datos

de variables y funciones que el proceso necesitará en memoria para el funcionamiento de

su programa.

La principal diferencia entre estos dos segmentos está en el tipo de variables y datos

que almacenan: mientras que el heap contiene variables, librerías y módulos globales y

estáticos, es decir que son accesibles en todo momento durante la ejecución del programa,

el stack contiene los argumentos, las variables y valores de retorno locales de la función

que se esté ejecutando.

En el caso de las variables contenidas en el stack su asignación de memoria es

automática y su duración en memoria termina cuando se abandona el alcance de su

función. Además si bien ambos segmentos de memoria pueden expandirse, lo hacen en la

misma dirección (como muestra la Figura 1).

Mapeo de Memoria

Otra función importante del sistema de manejo de memoria de linux es el mapeo de

archivos en memoria. Tanenbaum (2009) define el mapeo de memoria como “la asignación

de un archivo a una porción del espacio de direcciones de un proceso, de manera que se

pueda leer y escribir en el archivo como si fuera un arreglo de bytes en la memoria”. Este

mecanismo se usa para archivos, imágenes y bibliotecas compartidas. Es importante

resaltar que, teniendo en cuenta la paginación por demanda, el archivo/imagen en un

principio solo se encuentra asociado a la memoria virtual del proceso y solo es cargada en

la memoria principal cuando el proceso así lo solicita.

Acuña, Avila, Manzano, Martinez, Segovia


5
Fig 2. Dos procesos compartiendo un archivo.

Una de las ventajas que tiene el mapeo de memoria es que, recordando que cada marco

puede estar relacionado a más de un proceso, el mapeo de archivos en espacios de

memoria física permite que el acceso a estos archivos se pueda compartir entre los

procesos que lo necesiten.

2.2 LLamadas al Sistema: Administración de Memoria


2.2.1 Introducción

La Memoria Principal es un recurso valioso que se debe asignar y compartir entre los
procesos activos. Mantener en memoria la mayor cantidad posible de procesos, permite
hacer un uso eficiente del procesador y de los servicios de E/S. El micro no tendrá tiempos
ociosos pues siempre habrá un proceso para ejecutar. Por ello, una de las tareas más
importantes y complejas de un sistema operativo es la gestión de la memoria. El sistema
operativo Linux utiliza memoria virtual y para su administración, las técnicas de intercambio
y paginación por demanda. Para ello, se vale de las siguientes estructuras de datos:

· Tabla de páginas: describe las páginas virtuales del proceso.

· Descriptor de bloques de disco: describe el bloque de disco que contiene una página
determinada.

· Tabla de marcos de páginas: describe cada marco de página de la memoria real.

Acuña, Avila, Manzano, Martinez, Segovia


6
· Tabla de intercambios: registra las páginas que están en cada uno de los dispositivos
de intercambio, pues podemos definir más de uno.

Es importante aclarar que, aunque los comandos y las llamadas al sistema pueden tener el
mismo nombre, no hacen lo mismo. En general, los comandos en Linux se utilizan para
interactuar con el sistema operativo y obtener información sobre él, mientras que las
llamadas al sistema se utilizan para realizar operaciones en el sistema operativo, como la
gestión de procesos y memoria.

Las llamadas al sistema son la forma en que los programas de usuario interactúan con el
kernel del S.O. Las llamadas al sistema permiten que los programas de usuario soliciten
servicios del kernel, como reservar memoria, crear procesos, gestionar archivos y la
comunicación con dispositivos de hardware. Cuando un programa de usuario realiza una
llamada al sistema, se produce un cambio de modo de usuario a modo kernel. El modo
usuario es el modo en el que se ejecuta la mayoría de los programas de usuario, y el modo
kernel es el modo privilegiado en el que se ejecuta el kernel del sistema operativo.

Durante una llamada al sistema, el programa de usuario pasa el control al kernel, que
realiza la tarea solicitada. Una vez que se completa la tarea, el control se devuelve al
programa de usuario, y se produce un cambio de vuelta al modo de usuario. Las llamadas al
sistema se realizan a través de funciones de biblioteca en un programa de usuario.

2.2.2 LLamadas al Sistema para la administración de la memoria

Acuña, Avila, Manzano, Martinez, Segovia


7
En un sistema operativo, el administrador de memoria es responsable de administrar la
memoria del sistema y proporcionar a los procesos que la necesitan. Los procesos pueden
solicitar y liberar memoria en tiempo de ejecución mediante el uso de las llamadas al
sistema de administración de memoria.

Las llamadas al sistema de administración de memoria son una interfaz proporcionada por
el sistema operativo que permiten a los procesos solicitar y liberar memoria durante su
ejecución. Estas llamadas al sistema son críticas para la administración adecuada de la
memoria en un sistema operativo.

En el contexto de la programación en Linux, la llamada al sistema para administrar la


memoria se realiza a través de una función de biblioteca en un programa de usuario,
generalmente escrita en lenguajes de programación como C o C++. Por ejemplo, cuando un
programa necesita asignar memoria para almacenar datos, puede llamar a la función de
biblioteca "malloc" o "calloc". Estas funciones solicitan al sistema operativo la descarga de
un bloque de memoria y devuelven un puntero a la dirección de inicio de ese bloque de
memoria asignado.

Del mismo modo, cuando un programa necesita liberar la memoria que se ha asignado
previamente, puede llamar a la función de biblioteca "free". Esta función devuelve la
memoria al sistema operativo para su reutilización.

Las llamadas al sistema de administración de memoria más comunes son mmap, munmap,
brk, sbrk, malloc y free. Cada llamada al sistema realiza una tarea relacionada específica
con la liberación y liberación de memoria.

—------------

● mmap: La llamada al sistema “mmap” permite a un proceso asignar una región de


memoria virtual de tamaño específico. Esta región de memoria puede estar vacía o
puede estar inicializada a un archivo o a una región de memoria compartida. Esta
llamada al sistema es muy versátil y se utiliza para una variedad de propósitos,
como la eliminación de memoria para bloques de datos, buffers de entrada/salida,
pilas y regiones de memoria compartida.
■ MAP_HUGETLB: permite que los procesos reserven grandes
bloques de memoria utilizando páginas grandes en lugar de las
páginas regulares de tamaño más pequeño. Esto puede mejorar el
rendimiento y reducir la fragmentación de la memoria. También hay
otras opciones relacionadas con páginas grandes en Linux, como "

Acuña, Avila, Manzano, Martinez, Segovia


8
transparent huge pages " (THP), que permiten a los procesos utilizar
páginas grandes de forma transparente sin necesidad de modificar el
código de la aplicación.
● munmap: La llamada al sistema “munmap” se utiliza para liberar una región de
memoria virtual previamente utilizada por “mmap”. La región de memoria se
desasigna completamente, lo que significa que cualquier contenido que quedará en
la memoria se perderá. Si el proceso intenta acceder a esta región después de
haber sido liberada, se producirá un error de segmentación.
● brk/sbrk: Las llamadas al sistema “brk” y “sbrk” se utilizan para asignar y liberar
memoria dinámicamente en el segmento de datos de un proceso. El segmento de
datos es la región de memoria donde se almacenan las variables globales y los
datos del programa. La llamada al sistema “brk” establece la dirección del segmento
de datos final, mientras que “sbrk” se utiliza para aumentar o disminuir el tamaño del
segmento de datos. Es importante tener en cuenta que el uso de estas llamadas al
sistema para asignar memoria dinámicamente puede ser propenso a errores, como
fugas de memoria.
● malloc/free: Las llamadas al sistema “malloc” y “free” son una forma más segura y
sencilla de asignar y liberar memoria dinámicamente en Linux. La llamada al sistema
“malloc” se utiliza para asignar una cantidad específica de memoria dinámica al
proceso, mientras que “free” libera esa memoria. “malloc” también garantiza que la
memoria esté alineada adecuadamente para evitar errores de acceso a la memoria.

Las llamadas al sistema que acabamos de mencionar son las más comunes, pero también
mencionaremos algunas más:

● mlock: Esta llamada al sistema se utiliza para bloquear una página o un rango de
páginas de la memoria en la RAM para que no puedan ser intercambiadas con la
memoria secundaria (disco). Esta llamada al sistema es útil en situaciones en las
que se requiere un acceso rápido y constante a datos específicos, como en
aplicaciones de bases de datos.
● madvise: Esta llamada al sistema se utiliza para indicar al kernel cómo debe
manejar una región de memoria en particular. Por ejemplo, se puede especificar que
una página de memoria debe ser eliminada de la memoria caché o que se debe
liberar una región de memoria para su uso posterior. Esta llamada al sistema es útil
en situaciones en las que se desea un control más preciso sobre el uso de la
memoria.

Acuña, Avila, Manzano, Martinez, Segovia


9
● msync: Esta llamada al sistema se utiliza para sincronizar el contenido de una
región de memoria con el almacenamiento en disco. Por ejemplo, si una aplicación
ha modificado datos en una página de memoria que se encuentra en caché, la
llamada a msync asegurará que los cambios se escriban en el disco antes de que se
libere la memoria.
● mincore: Esta llamada al sistema se utiliza para determinar si una página de
memoria específica se encuentra actualmente en la memoria caché. Esta llamada al
sistema puede ser útil en situaciones en las que se desea conocer el estado de la
memoria caché para un proceso en particular.
● mremap: Esta llamada al sistema se utiliza para cambiar el tamaño de una región
de memoria que se ha asignado previamente. La llamada a mremap es útil cuando
se necesita aumentar o disminuir el tamaño de una región de memoria sin tener que
copiar los datos a otra ubicación.

2.2.3 Consecuencias de un mal uso

Algo de lo que hay que tener mucho cuidado es sobre el mal uso de las llamadas al sistema
para administrar la memoria, esto puede tener graves consecuencias para el rendimiento y
la estabilidad del sistema. A continuación, mencionaremos algunas de las consecuencias
del mal usos de estas llamadas al sistema:

● Fugas de memoria: Si no se libera correctamente la memoria que se ha asignado


dinámicamente, se pueden producir fugas de memoria. Las fugas de memoria
ocurren cuando un proceso asigna memoria dinámicamente pero no la libera, lo que
resulta en una pérdida de memoria y una disminución del rendimiento del sistema a
medida que se agota la memoria disponible.
● Error de segmentación: Si un proceso intenta acceder a una región de memoria
que no ha sido visible o que ha sido liberada previamente, puede ocurrir un error de
segmentación. Este tipo de error puede hacer que el proceso se bloquee o se cierre
inesperadamente, lo que puede causar la pérdida de datos y la interrupción de otros
procesos en el sistema.
● Corrupción de datos: El uso incorrecto de las llamadas al sistema para administrar
la memoria también puede resultar en la corrupción de datos. Si se accede a una
región de memoria que ha sido liberada previamente, los datos almacenados allí
pueden ser sobrescritos o eliminados, lo que puede resultar en la pérdida de datos o
en la corrupción de los mismos.

Acuña, Avila, Manzano, Martinez, Segovia

10
● Rendimiento deficiente: Si se asigna y libera memoria dinámicamente de manera
ineficiente, el rendimiento del sistema puede disminuir significativamente. Esto se
debe a que la protección y liberación ineficiente de memoria puede provocar una
fragmentación de la memoria, lo que dificulta la protección de memoria contigua para
procesos que la requieren. Esto puede llevar a cabo una disminución general del
rendimiento del sistema.

2.3 Implementación de la administración de memoria


Por lo general, en máquinas de 32 bits que corren Linux, a cada proceso se le da 3GB de
espacio de direcciones virtuales, donde 1Gb se reserva para sus tablas de páginas y otros
datos del kernel.
Cuando el proceso se ejecuta en modo usuario, el gigabyte del kernel no es accesible, en
cambio una vez que el proceso está en el kernel, podrá usarlo. Por lo general, la memoria
del kernel reside en la memoria física inferior, pero se asigna en el gigabyte superior del
espacio de direcciones virtuales de cada proceso. Dicho espacio se crea en el mismo
momento en el que se crea el proceso y se sobreescribe en una llamada al sistema exec.

Figura X - Espacio de direcciones virtuales destinada para el espacio de usuario y del


kernel en arquitecturas de 32 bits y 64 bits.

El kernel de Linux proporciona un espacio de direcciones virtual independiente para cada


proceso siendo este espacio de direcciones continuo, De esta manera el proceso puede

Acuña, Avila, Manzano, Martinez, Segovia

11
acceder fácilmente a la memoria virtual. El interior del espacio de direcciones virtuales se
divide en Espacio de kernel y espacio de usuario, los procesadores con diferentes
longitudes de palabra tienen diferentes espacios de direcciones, como ejemplo tenemos a
los sistemas más comunes de 32 y 64 bits como se muestra en la figura.
A continuación, se va a explicar la implementación de varios mecanismos en el Kernel de
Linux que son los responsables de administrar la memoria.

2.3.1 Administración de la memoria física


No toda memoria física se puede tratar de la misma forma, Linux trabaja con tres zonas de
memoria:
1. ZONE_DMA: páginas que se pueden utilizar para operaciones de DMA.
2. ZONE_NORMAL: páginas normales que se asignan de la manera usual.
3. ZONE_HIGHMEM: páginas con direcciones de memoria superior, que no se asignan de
manera permanente.

Los límites exactos y la distribución de las zonas de memoria dependen de la arquitectura.


A continuación se procederá a explicar para dos tipos de arquitecturas básicas (x86) de 32
bits y 64 bits.

Figura X - Distribución de las zonas en las arquitectura de x86 de 32 bits y de 64 bits.

En el hardware x86, ciertos dispositivos pueden realizar operaciones de DMA sólo en los
primeros 16 MB del espacio de direcciones.Además, el hardware no puede asignar en
forma directa las direcciones de memoria por encima de 896 MB, por lo que
ZONE_HIGHMEM se encuentra arriba de esta marca. ZONE_NORMAL es cualquier
ubicación entre las dos zonas anteriores. Por lo tanto, en las plataformas (x86) los primeros

Acuña, Avila, Manzano, Martinez, Segovia

12
896 MB del espacio de direcciones de Linux se asignan en forma directa, mientras que los
128 MB restantes del espacio de direcciones del kernel se utilizan para acceder a las
regiones de la memoria superior. El kernel mantiene una estructura de zona para cada una
de las tres zonas y puede realizar asignaciones de memoria para las tres zonas por
separado.
En las de 64 bits, la zona ZONE_DMA corresponde a las direcciones físicas de 0 a 16 MB.
La zona ZONE_DMA32 existe únicamente en las plataformas de 64 bits de 16 MB a 4 GB.
La zona ZONE_NORMAL es toda la RAM disponible más allá de 4 GB. La memoria
principal en Linux está dividida en tres partes: las dos primeras partes (kernel y mapa de
memoria) están residentes (fijadas) en la memoria y el resto de la memoria se divide en
marcos de página. El kernel mantiene un mapa de la memoria principal.
Linux mantiene un arreglo de descriptores de páginas, de tipo página para cada marco de
página física en el sistema, conocido como mem_map. Cada descriptor de página
contiene un apuntador al espacio de direcciones al que pertenece, en caso de que la página
no esté libre, un par de apuntadores que le permitan formar listas doblemente enlazadas
con otros descriptores, por ejemplo para mantener juntos todos los marcos de página libres,
y unos cuantos campos más. El tamaño del descriptor de página es de 32 bytes, por lo que
el mem_map completo puede consumir menos de 1% de la memoria física (para un marco
de página de 4 KB).
Linux, también, mantiene un descriptor de zona, que contiene información sobre el uso de la
memoria dentro de cada zona, como el número de páginas activas e inactivas. Este
descriptor contiene un arreglo de áreas libres. El i-ésimo elemento en este arreglo identifica
el primer descriptor de página del primer bloque de 2i páginas libres. Como puede haber
varios bloques, Linux utiliza el par de apuntadores de descriptores de página en cada
elemento page para enlazarlos entre sí. Esta información se utiliza en las operaciones de
asignación de memoria que Linux proporciona.
En las plataformas UMA, Linux describe toda la memoria a través de un descriptor de nodo.
Los primeros bits dentro de cada descriptor de página se utilizan para identificar el nodo y la

Acuña, Avila, Manzano, Martinez, Segovia

13
zona a los que pertenece el marco de página.

Figura X - Representación de la memoria principal de Linux

Linux utiliza un esquema de paginación de cuatro niveles. Cada dirección virtual se divide
en cinco campos, como se puede observar en la Figura X. Los campos de los directorios se
utilizan como un índice, del cual hay uno para cada proceso. El valor que contiene apunta a
un nuevo directorio del siguiente nivel, que se vuelve a indexar. La entrada seleccionada en
el directorio de la página intermedia apunta a la tabla de páginas final, que se indexa
mediante el campo de página de la dirección virtual.La entrada que se encuentra aquí
apunta a la página requerida.En síntesis, las primeras 4 entradas se utilizan para
seleccionar páginas y el último índice representa el desplazamiento dentro de la página.

Acuña, Avila, Manzano, Martinez, Segovia

14
Figura X. Linux utiliza una tabla de páginas de cuatro niveles.

Por otro lado, la memoria física se utiliza para varios fines. El kernel en sí está fijo en su
totalidad; ninguna parte de él se página hacia fuera de la memoria. El resto de la memoria
está disponible para las páginas de usuario, la caché de paginación y otros fines.
Linux también acepta los módulos que se cargan en forma dinámica los cuales pueden
tener un tamaño arbitrario y a cada uno se les debe asignar una pieza contigua de memoria
del kernel, por esto Linux, administra la memoria física de forma tal que pueda adquirir una
pieza de memoria de un tamaño que se arbitrario cuando lo desee y para esto utiliza el
algoritmo de colegas (buddy algorithm), el cual será analizado a continuación.

2.3.2 Mecanismos de asignación de memoria


2.3.2.1 Algoritmo de colegas
El asignador de páginas en Linux opera mediante el algoritmo de colegas, de amigos o de
descomposición binaria. El sistema de asignación de colegas es un algoritmo en el que un
bloque de memoria más grande se divide en partes pequeñas para satisfacer la solicitud.
Este algoritmo se utiliza para ofrecer el mejor ajuste. Las dos partes más pequeñas del
bloque son del mismo tamaño y se denominan colegas o amigos. De la misma manera, uno
de los dos colegas se dividirá en partes más pequeñas hasta que se cumpla la solicitud. El
beneficio de esta técnica es que los dos colegas pueden combinarse para formar el bloque
de mayor tamaño de acuerdo con la solicitud de memoria.
La Figura X nos muestra un ejemplo cuando el sistema intenta hacer una asignación de 8
páginas en memoria (la asignación siempre se corresponde con una potencia de dos), esta
divide a la única pieza contigua de 64 páginas en dos bloques o colegas de 32 páginas,
como esta cantidad sigue siendo mayor que las 8 que deben asignarse la división vuelve a
Acuña, Avila, Manzano, Martinez, Segovia

15
efectuarse en el bloque de la parte baja de la memoria, ahora se tienen dos colegas más de
16 páginas cada uno. Se vuelve a efectuar una partición más del bloque de memoria de 16
páginas inferior y se obtienen dos bloques de 8 páginas, es en esta instancia en que se
hace efectiva la asignación. Posteriormente se hace un nueva solicitud de 8 páginas de
memoria, que como ya se tiene un bloque de tal tamaño la asignación ahora es directa. La
próxima petición de memoria necesita 4 páginas de memoria, por lo que el bloque inferior
libre de 16 páginas se divide sucesivamente hasta obtener bloques del tamaño requerido y
se efectúa la correspondiente asignación. En la siguiente instancia uno de los bloques de 8
páginas anteriormente asignado se libera, y a continuación se libera su colega también de 8
páginas, al provenir estos bloques de una misma división se procede con la combinación de
ambos para formar el bloque de 16 páginas original. A este proceso se le conoce como
fusión.

Figura X - Operación del algoritmo de colegas.

Ventajas del algoritmo de colegas


● En comparación con otras técnicas más simples, como la asignación dinámica, el sistema
de memoria de amigos tiene poca fragmentación externa.
● El sistema de asignación de memoria de amigos se implementa con el uso de un árbol
binario para representar bloques de memoria dividida usados o no usados.
● El sistema de amigos es muy rápido para asignar o desasignar memoria.
● En los sistemas de amigos, el costo de asignar y liberar un bloque de memoria es bajo en
comparación con el de los algoritmos de mejor ajuste o de primer ajuste.
● Otra ventaja es la fusión.
● El cálculo de direcciones es sencillo.

Acuña, Avila, Manzano, Martinez, Segovia

16
Inconvenientes
El principal inconveniente del sistema de colegas es la fragmentación interna, ya que se
adquiere un bloque de memoria más grande y luego se requiere. Por ejemplo, si se realiza
una solicitud de 36 páginas, sólo puede satisfacerse con un segmento de 64 páginas y se
desperdicia la memoria restante.

2.3.2.2 Asignación de losas


Una segunda estrategia para asignar memoria del kernel se conoce como asignador de
losas (slab allocator), o también denominada asignación de franjas. Esta elimina la
fragmentación causada por asignaciones y desasignaciones. Este método se utiliza para
retener la memoria asignada que contiene un objeto de datos de cierto tipo para su
reutilización en asignaciones posteriores de objetos del mismo tipo. En la asignación de
losas, se preasignan fragmentos de memoria adecuados para adaptarse a objetos de datos
de cierto tipo o tamaño. La caché no libera el espacio inmediatamente después de su uso,
aunque realiza un seguimiento de los datos que se requieren con frecuencia para que cada
vez que se solicite, los datos lleguen muy rápido. Dos términos requeridos son:
● Losa: una losa se compone de una o más páginas físicamente contiguas. La losa
es el contenedor real de datos asociados con objetos del tipo específico de caché
contenedor.
● Caché: el caché representa una pequeña cantidad de memoria muy rápida. Una
caché consta de una o más losas. Hay una única caché para cada estructura de
datos del kernel única. Por ejemplo, una caché para la estructura de datos que
representa los descriptores de procesos, caché separado para objetos de archivo,
caché separado para semáforos, etc.
Cada caché se llena con objetos que son instancias de la estructura de datos del kernel que
representa la caché. La Figura X muestra una representación visual y la relación de los
elementos que se describen.

Acuña, Avila, Manzano, Martinez, Segovia

17
Figura X - ASIGNADOR DE LOSAS (Slab Allocator)
El algoritmo de asignación de losas usa cachés para almacenar objetos del kernel. Cuando
se crea una caché, una serie de objetos que inicialmente están marcados como libres se
asignan a la caché. La cantidad de objetos en la caché depende del tamaño de la losa
asociada.
En Linux, una losa puede estar en uno de tres estados posibles:
● Llena: todos los objetos de la losa están marcados como usados.
● Vacío: todos los objetos de la losa están marcados como libres.
● Parcial: la losa consta de ambos.
El asignador de losa primero intenta satisfacer la solicitud con un objeto libre en una losa
parcial. Si no existe, se asigna un objeto libre desde una losa vacía. Si no hay losas vacías
disponibles, se asigna una nueva losa de páginas físicas contiguas y se asigna a una
caché.
Beneficios de la asignación de losas
● No se desperdicia memoria debido a la fragmentación porque cada estructura de datos
del kernel única tiene una caché asociada.
● La solicitud de memoria se puede satisfacer rápidamente.
● El esquema de asignación de losas es particularmente efectivo para administrar cuando
los objetos se asignan o desasignan con frecuencia. El acto de asignar y liberar memoria
puede ser un proceso que requiere mucho tiempo. Sin embargo, los objetos se crean de
antemano y, por lo tanto, se pueden asignar rápidamente desde la caché. Cuando el kernel
Acuña, Avila, Manzano, Martinez, Segovia

18
ha terminado con un objeto y lo libera, se marca como libre y regresa a su caché, lo que lo
hace disponible inmediatamente para una solicitud posterior del kernel.
2.3.3 Representación del espacio de direcciones virtuales
El espacio de direcciones virtuales está dividido en áreas o secciones homogéneas,
contiguas y alineadas por páginas. Es decir, cada área consiste en una serie de páginas
consecutivas (una detrás de otra) que cuentan con las mismas propiedades tanto de
protección como de paginación.
El interior del espacio de direcciones virtuales se divide en espacio de kernel (de color
morado), y espacio de usuario (de color azul). A su vez, este espacio de usuario se puede
subdividir en:
1. Sección de solo lectura (incluye código y constantes).
2. Segmento de datos (incluye las variables globales, etc.).
3. El montón (comienza desde la dirección baja y crece hacia arriba e incluye la memoria
asignada dinámicamente).
4. La sección de mapeo de archivos (comienza desde la dirección alta y crece hacia
abajo e incluidas las bibliotecas dinámicas, la memoria compartida, etc.).
5. Pila (el tamaño de la pila es fijo, y generalmente de 8 MB, incluye el contexto de las
variables locales y las llamadas a funciones).

Figura X - Distribución interna de la memoria virtual.

Acuña, Avila, Manzano, Martinez, Segovia

19
Puede haber hoyos en el espacio de direcciones virtuales entre las áreas, por lo tanto,
cualquier referencia de memoria a un hoyo producirá un fallo de página fatal. El tamaño de
página es fijo.
Cada área o segmento se describe en el kernel mediante una entrada vm_area_struct.
Todas las entradas vm_area_struct se enlazan entre sí en una lista ordenada por dirección
virtual, de tal forma que se puedan encontrar todas las páginas. Cuando la lista se hace
muy grande (más de 32 entradas), se crea un árbol para agilizar la búsqueda.
La entrada vm_area_struct se encarga de listar las distintas propiedades del área, y éstas,
incluyen el modo de protección (por ejemplo, sólo lectura o lectura/escritura), si se
encuentra fijada en la memoria, y en qué dirección aumenta su tamaño (hacia arriba para
los segmentos de datos, hacia abajo para las pilas). Además, también registra si el área
tiene asignado un almacenamiento de respaldo en el disco, y de ser así, cuál es su
ubicación.
Existe un descriptor de memoria de nivel superior denominado mm_struct, el cual se
encarga de recopilar información sobre todas las áreas de memoria virtual que pertenecen a
un espacio de direcciones, información sobre los distintos segmentos (texto, datos, pila),
información sobre los usuarios que comparten este espacio de direcciones, etc. Se puede
acceder a todos los elementos vm_area_struct de un espacio de direcciones por medio de
su descriptor de memoria de dos formas:
1. Listas enlazadas: se organizan en listas enlazadas ordenadas por direcciones de
memoria virtual. Este método es útil cuando se requiere el acceso a todas las áreas de
memoria virtual, o cuando el kernel busca asignar una región de memoria virtual de un
tamaño específico.
2. Árbol binario rojo-negro: es una estructura de datos optimizada para búsquedas
rápidas. Este método se utiliza cuando hay que acceder a una memoria virtual específica. Al
permitir el acceso a los elementos del espacio de direcciones del proceso por medio de
estos dos métodos, Linux utiliza más estado por proceso, pero permite que las distintas
operaciones del kernel utilicen el método de acceso más eficiente para la tarea que se vaya
a realizar.

Acuña, Avila, Manzano, Martinez, Segovia

20
2.4 Paginación

Es un esquema de gestión de memoria que permite que el espacio de direcciones físicas de


un proceso no sea contiguo, evitando el problema de tener que encontrar fragmentos de
memoria de un determinado tamaño en el almacén de respaldo. El almacén de respaldo (al
igual que la memoria principal) tiene problemas de fragmentación, pero con la complicación
de que es mucho más grande y mucho más lenta lo cual hace que la estrategia de la
compactación sea impracticable en los periodos de tiempos tan pequeños que requieren los
procesos.

2.4.1 Método Básico

La paginación descompone la memoria física en una serie de bloques de tamaño fijos


llamados “marcos” y descompone la memoria lógica en bloque del mismo tamaño
denominados “páginas”. El almacén de respaldo está también dividido en bloques de
tamaños fijos de la misma longitud que los marcos de memoria.

Las direcciones generadas por la CPU están divididas en dos partes, el “número de página
(d)” y el “desplazamiento de página (d)”. El sistema mantiene una estructura de datos
llamada Tabla de Páginas la cual almacena los números de páginas a manera de índice
hacia la memoria física, esta dirección es combinada con el desplazamiento de página para
poder localizar la dirección de la memoria física.

Acuña, Avila, Manzano, Martinez, Segovia

21
El tamaño de página es normalmente un múltiplo de 2, esto facilita el hardware de la
conversión y suma de las direcciones.

Con este esquema no existe fragmentación externa, pero sigue existiendo la fragmentación
interna, por ejemplo, si el tamaño de un proceso no coincide exactamente con el tamaño de
la suma de los marcos asignados entonces el último marco podría no quedar
completamente lleno, en el peor de los casos el tamaño de un proceso podría ser n páginas
más un byte requiriendo así n+1 marcos, dando como resultado una fragmentación interna
de prácticamente un marco.

Entonces se podría esperan un promedio de fragmentación interna de media página por


proceso. Una táctica para atenuarlo sería utilizar tamaños de páginas más pequeños, pero
esto tiene como contra que mientras más página haya se necesita dedicar mas recursos
para su gestión, en contraria los recursos adicionales se reducen al incrementar el tamaño
de las páginas. Es oportuno destacar que las operaciones de E/S de disco son más
eficientes cuanto mayor sea el número de datos transferidos, por todo esto en la actualidad
los tamaños de las páginas de los nuevos sistemas son cada vez más grandes.

Acuña, Avila, Manzano, Martinez, Segovia

22
2.4.1 Páginas compartidas

La ventaja en este aspecto es poder compartir páginas en común

El término código reentrante o código puro es código que nunca cambia durante la
ejecución, entonces dos o más procesos pueden compartir y ejecutar código de una página
al mismo tiempo. Cada proceso pensara que la pagina pertenece a su espacio de
direcciones lógico mientras que en realidad físicamente los procesos estarán haciendo uso
de un mismo marco.

2.4.1 Estructura de la tabla de página.

Paginación jerárquica: los sistemas modernos soportan direcciones lógicas muy


grandes, por ejemplo un sistema con un espacio lógico de 32bits y un tamaño de
página de 4kB puede estar compuestas de 1048576 de entradas, esta cantidad de
entrada se hace complicada de manejar, una solución simple consiste en dividir la
tabla en fragmentos más pequeños así utilizar un algoritmo de paginación de dos
niveles en la que la propia página está también paginada.

Conclusión
Para concluir este informe se entiende que:

Acuña, Avila, Manzano, Martinez, Segovia

23

También podría gustarte