Documente Academic
Documente Profesional
Documente Cultură
DE LA GESTIN DE
MEMORIA EN LINUX
NDICE
1. INTRODUCCIN ........................................................................................................................ 3
2. EL TRATAMIENTO DE LA MEMORIA EN LINUX ........................................................................ 4
3. LAS PGINAS ............................................................................................................................. 4
4. LAS ZONAS ................................................................................................................................ 5
5. FUNCIONES EN MEMORIA........................................................................................................ 6
6. LA FUNCIN kmalloc ................................................................................................................ 6
7. LA FUNCIN vmalloc ................................................................................................................ 7
8. EL SLAB LAYER ........................................................................................................................... 7
9. ASIGNACIONES ESTTICAS EN LA PILA .................................................................................... 9
10. PROYECCIONES EN ALTA MEMORIA .................................................................................... 10
11. ASIGNACIONES POR CPU ...................................................................................................... 11
12. RESUMEN: LAS FUNCIONES PARA GESTIONAR LA MEMORIA ............................................ 13
13. CONCLUSIN......................................................................................................................... 13
1. INTRODUCCIN
Las reservas y asignaciones de memoria en el ncleo o kernel no son tan fciles como
se realizan estos mismos procedimientos fuera de este. Esto se debe a que el ncleo carece de
lujos de los que puede disfrutar el espacio de usuario. A diferencia de este ltimo, el ncleo no
dispone siempre de la capacidad de reservar memoria con facilidad. Por ejemplo, no puede
tratar los errores con facilidad y con frecuencia no puede dormirse o pausar su
funcionamiento.
Debido a estas limitaciones, y a la necesidad de un esquema de asignacin de memoria
ligero, hacerse con memoria en el ncleo es bastante ms complicado que en el espacio de
usuario.
En las futuras pginas se discutirn los distintos mtodos utilizados para obtener
memoria dentro del ncleo. Antes de profundizar en todas estas funciones disponibles
actualmente, tambin se tendr que entender cmo maneja el ncleo de Linux la memoria.
3. LAS PGINAS
El ncleo trata las pginas fsicas como la unidad bsica de la gestin de memoria. A
pesar de que la unidad mnima direccionable del procesador es normalmente un byte, o una
palabra en general, la unidad de gestin de memoria (MMU) con frecuencia maneja pginas.
Por tanto, la MMU mantiene las tablas de paginacin del sistema con nivel de tamaos de
pgina. En lo relativo a la memoria virtual, las pginas son la menor unidad significativa.
Cada arquitectura define su propio tamao de pgina. Muchas de ellas incluso admiten
varios tamaos distintos. La mayora de arquitecturas de 32 y 64 bits presentan tamaos de 4
y 8 KB, respectivamente.
El kernel de Linux representa todas las pginas del sistema definiendo la estructura
page (struct page), definida en la biblioteca <linux/mm_types.h>. En la estructura
podemos destacar los siguientes elementos:
unsigned long flags: Este campo almacena el estado de la pgina. Entre estos
flags se incluyen, por ejemplo, si la pgina est bloqueada en memoria. La variable admite 32
flags distintos activados simultneamente.
atomic_t _count: Este campo almacena el nmero de referencias que hay a la
pgina. Esta variable es negativa cuando no se est usando la pgina, en cuyo caso estara
disponible para una nueva asignacin de memoria.
void *virtual: Este campo apunta a la direccin virtual de la pgina.
Normalmente, es simplemente la direccin de la pgina en la memoria virtual.
La estructura page representa pginas fsicas, no virtuales. El ncleo utiliza esta
estructura de datos para describir la pgina fsica asociada, no los datos contenidos en su
interior. Con la estructura, el ncleo realiza un seguimiento de todas las pginas del sistema,
puesto que necesita conocer si una pgina est libre (no asignada). Y, en caso de no estarlo,
necesita saber quin es su propietario. Entre los posibles propietarios se incluyen los procesos
de espacios de usuario, datos del ncleo asignados dinmicamente, cdigo esttico del ncleo,
etc. Aunque en un primer momento se pueda pensar que se utiliza una gran cantidad de
4. LAS ZONAS
Debido a las limitaciones del hardware, el kernel no puede tratar a todas las pginas
de la misma forma. Debido a esto, divide las pginas en diferentes espacios, que denominamos
zonas. El ncleo usa estas zonas para agrupar pginas con propiedades en comn. En
particular, Linux tiene que ocuparse de dos defectos del hardware relacionados con el
direccionamiento a memoria. Por un lado, algunos dispositivos hardware pueden realizar un
acceso directo a memoria solo en determinadas direcciones. Por otro lado, algunas
arquitecturas pueden direccionar fsicamente mayores cantidades de memoria de lo que lo
hacen virtualmente, y por tanto, hay memoria que no est permanentemente asignada en el
espacio de direcciones del ncleo.
Debido a estas restricciones, Linux cuenta con cuatro zonas de memoria principales:
- ZONE_DMA: contiene las pginas que pueden someterse a un acceso directo a memoria.
- ZONE_DMA32: Como la anterior, pero solo accesible para dispositivos de 32-bit.
- ZONE_NORMAL: Contiene las pginas normales, que son asignadas con regularidad.
- ZONE_HIGHMEM: Contiene las pginas que no se asignan permanentemente al espacio de
direcciones del ncleo.
El uso y la disposicin actual de las zonas de memoria depende de la arquitectura. Por
ejemplo, algunas arquitecturas no necesitan de zona DMA al no tener problemas para realizar
el acceso directo a memoria en cualquier direccin de memoria.
Linux divide en zonas las pginas del sistema para tener un lugar comn donde realizar
las asignaciones necesitadas. As, a la hora de asignar, al ncleo le basta con tomar el nmero
de pginas necesarias de la zona conveniente. Las zonas no tienen ninguna relevancia fsica,
sino que son simplemente agrupaciones lgicas usadas por el ncleo para llevar la cuenta de
las pginas.
Aunque algunas asignaciones requieren las pginas de alguna zona particular, otras
podran tomar las pginas de varias zonas posibles, pero nunca mezclando las pginas de
ambas zonas. Por ejemplo, una asignacin normal, en lugar de en la zona normal, se podra
realizar sobre pginas del DMA. En ningn caso se tomaran a la vez pginas de ambas zonas.
Evidentemente, el ncleo optara en la mayora de los casos para este ejemplo por usar la zona
normal, para reservar las de la zona DMA a aquellas que realmente lo necesiten.
Cada zona se representa con la estructura struct zone, definida en
<linux/mmzone.h>. Los campos ms importantes de esta estructura son:
5. FUNCIONES EN MEMORIA
A continuacin vamos a ver las distintas interfaces que se implementan en el ncleo
para asignar y liberar memoria dentro del mismo. El ncleo proporciona un mecanismo de
bajo nivel para solicitar memoria, junto con varias interfaces para acceder a l. Todas estas
interfaces asignan memoria a nivel de tamaos de pgina y estn declaradas en <linux/gfp.h>.
La funcin esencial es struct page * alloc_pages(gfp_t gfp_mask, unsigned int order). Esta
funcin reserva 2 pginas fsicas contiguas y devuelve un puntero a la primera estructura
reservada. En caso de error, el puntero es nulo. La pgina dada se puede convertir a su
direccin lgica con la funcin void * page_address(struct page *page), que devuelve un
puntero a la direccin lgica correspondiente. Tambin es posible obtener pginas rellenas de
ceros (todos los bit desactivados), lo cual es til para asegurar que no se compromete la
seguridad del sistema. Para eso tenemos la funcin unsigned long get_zeroed_page(unsigned
int gfp_mask).
A la hora de liberar las pginas utilizadas, el kernel dispone de una familia de funciones,
entre las que destacan: void __free_pages(struct page *page, unsigned int order); void
free_pages(unsigned long addr, unsigned int order); void free_page(unsigned long addr);
Solo se deben liberar las pginas que han sido asignadas previamente.
6. LA FUNCIN kmalloc
La funcin kmalloc()es similar a la conocida funcin malloc()del espacio de usuario.
Con la excepcin de un parmetro adicional de flags. Es una interfaz simple para obtener
memoria en el ncleo en bloques de tamao de bytes. Su prototipo es: void * kmalloc(size_t
size, gfp_t flags). Devuelve un puntero a una direccin de memoria que tiene al menos la
cantidad de bytes especificada de longitud. La regin de memoria asignada est contigua
fsicamente en memoria. En caso de error se devuelve un puntero nulo.
Los flags que se pueden especificar en todas las funciones anteriores vienen definidos
como unsigned int, y se dividen en tres categoras: modificadores de accin,
modificadores de zona y tipos. Los modificadores de accin especifican cmo debe el ncleo
reservar la memoria solicitada. Los modificadores de zona especifican desde dnde se debe
asignar la memoria. Finalmente, los flags de tipo permiten simplificar la especificacin de
mltiples modificadores.
7. LA FUNCIN vmalloc
La funcin vmalloc funciona de forma similar a kmalloc, con la diferencia de que solo
asigna memoria que se encuentra virtualmente contigua y no necesariamente contigua
fsicamente. Hace esto asignando principalmente cantidades de memoria fsica no contiguas y
arreglando las tablas de paginacin para formar un bloque contiguo del espacio de direcciones
lgicas.
En su mayora, solo los dispositivos hardware requieren asignaciones en memoria
fsica contigua. En consecuencia, cualquier regin de memoria con la que puedan trabajar los
dispositivos hardware debe aparecer como un bloque fsicamente contiguo y no meramente
virtual. Los bloques de memoria usados solo por el software son receptivos en el uso de
memoria que solo se encuentra contigua virtualmente. Al programar no se aprecia la
diferencia: toda la memoria se presenta en el ncleo como lgicamente contigua.
A pesar de que la memoria fsicamente contigua solo se requiere en ciertos casos, la
mayor parte del ncleo recurre a la funcin kmalloc para obtener memoria. El prototipo de
esta nueva funcin es: void * vmalloc(unsigned long size). Su funcionamiento es anlogo al
de la funcin malloc del espacio de usuario. Para liberar una asignacin realizada con esta
funcin, se utiliza void vfree(const void *addr).
8. EL SLAB LAYER
La reserva y liberacin de memoria es una de las operaciones ms comunes en
cualquier ncleo. Para facilitar estas operaciones, se introducen con frecuencia las
denominadas listas libres (free lists). Estas listas contienen un bloque de estructuras de datos
ya reservado y disponible para su uso. Cuando se requiere una nueva instancia de la
estructura, bastara con tomar una de las estructuras de la lista en lugar de reasignar la
cantidad suficiente de memoria necesaria. Cuando ya no se necesitan los datos, bastara con
volver a la lista libre en lugar de liberar la memoria.
Uno de los principales problemas de estas listas en el ncleo es que no se puede tener
un control global sobre ellas. Para remediar esto, el ncleo de Linux proporciona el
denominado slab layer. Este concepto acta como una capa genrica de almacenamiento de
estructuras de datos.
El slab layer trata de hacer uso de varios principios bsicos, entre los que destacan:
- Las estructuras de datos usadas frecuentemente tienden a ser reservadas y liberadas
luego. Resulta til que se almacenen en cach.
- Las listas libres proporcionan una actuacin mejorada durante reservas y liberaciones
frecuentes de memoria ya que un objeto liberado puede ser devuelto de forma inmediata a la
prxima asignacin en memoria.
- Si se est al tanto de conceptos como el tamao, el tamao de pgina o el tamao
total de cach se pueden tomar decisiones ms inteligentes.
El slab layer reparte los diferentes objetos en grupos denominados cachs, cada uno
de los cuales almacena un tipo diferente de objeto. Hay una cach por tipo de objeto. Cada
cach se divide en bloques (slabs), compuestos por una o ms pginas contiguas fsicamente.
Normalmente, cada bloque tiene solo una pgina. Cada cach se compone de mltiples
bloques.
Cada bloque contiene cierto nmero de objetos, que son las estructuras de datos a
almacenar. Los bloques pueden encontrarse en tres estados distintos: vaco, lleno o parcial. Un
bloque lleno tiene todos sus objetos asignados en memoria. Un bloque vaco tiene todos sus
objetos libres. Un bloque parcial tiene objetos asignados y objetos libres. Cuando desde el
ncleo se solicita un nuevo objeto, se busca un bloque parcial para realizar la solicitud, si
existe. En caso de no existir, se realiza desde un bloque vaco. Si no existen, se crea un bloque
nuevo. Esta estrategia reduce la fragmentacin.
(*ctor)(void *)).
Una vez la cach ha sido creada, se puede obtener un objeto a travs de la funcin
que devuelve un puntero
a un objeto de la cach pasada como argumento. Si no quedan objetos libres, se obtendrn
nuevas pginas mediante las funciones mencionadas previamente. Para liberar posteriormente
el objeto y devolverlo a su slab de origen, se usa la funcin void kmem_cache_free(struct
kmem_cache *cachep, void *objp), que marca el objeto pasado en el segundo argumento como
libre.
void * kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags),
El tamao de las pilas del ncleo para cada proceso depende de la arquitectura y de
una opcin en tiempo de compilacin. Histricamente, el ncleo ha tenido dos pginas por
proceso. Sin embargo, pronto se introdujo una opcin para cambiar el nmero de pginas por
proceso a una sola. Se debi a dos razones. La primera es que se reduce el consumo de
Por ejemplo, en la arquitectura x86, toda la memoria fsica ms all de los 896 MB es
alta memoria y no se proyecta permanentemente ni automticamente en el espacio de
direcciones del ncleo, a pesar de que estos procesadores son capaces de direccionar hasta 4
GB de RAM fsica. Despus de ser reservadas, estas pginas deben proyectarse en el espacio
de direcciones lgicas del ncleo.
Para proyectar una pgina dada sobre el espacio de direcciones del ncleo se utiliza la
funcin void *kmap(struct page *page), declarada en <linux/highmem.h>. Esta funcin
funciona tanto en alta como baja memoria. Si la pgina pertenece a la baja memoria,
simplemente devuelve su direccin virtual. Si pertenece a la alta memoria, se crea una
proyeccin permanente y se devuelve su direccin. La funcin acta bien solo en el contexto
de procesos. Como el nmero de proyecciones permanentes es limitado, la alta memoria debe
ser desasignada cuando ya no se necesite. Esto se hace mediante la siguiente funcin, que
desasigna la pgina dada: void kunmap(struct page *page).
Cuando se debe crear una proyeccin pero el contexto actual no puede detenerse, el
ncleo proporciona proyecciones temporales. Estas son un conjunto de zonas reservadas que
pueden contener una proyeccin temporal. El ncleo puede proyectar automticamente una
pgina de alta memoria en uno de estas proyecciones reservadas. Una proyeccin temporal se
establece mediante la funcin void *kmap_atomic(struct page *page, enum km_type type). El
segundo parmetro es una enumeracin que describe el propsito de la proteccin. La
10
11
De la misma forma tambin tenemos la opcin de crear variables por CPU en tiempo
de ejecucin. El ncleo implementa un asignador dinmico de memoria para crear datos por
CPU. Estas rutinas crean instancias de la memoria requerida para cada procesador en los
sistemas. Las y macros ms destacadas, que vienen declaradas tambin en <linux/percpu.h>,
son void *alloc_percpu(type), void *__alloc_percpu(size_t size, size_t align) y void
free_percpu(const void *). La primera es una macro que reserva memoria para una instancia
del tipo dado en cada procesador del sistema. Es una simplificacin de la segunda funcin, que
reserva una cantidad de memoria especificada por los parmetros en cada procesador. La
ltima llamada libera los datos en todos los procesadores.
Las dos primeras llamadas para reservar memoria devuelven un puntero, que se usa de
forma indirecta para referirnos a los datos por CPU creados dinmicamente. El ncleo
proporciona las macros get_cpu_var y put_cpu_var. La primera devuelve un puntero a la
instancia especfica en los datos del actual procesador y desactiva la apropiacin del ncleo,
que se restablece con la segunda funcin.
Varios son los beneficios del uso de los datos por CPU. El primero es la reduccin de
las necesidades de bloqueos, cerrojos y otras estructuras similares. Segn la forma en que los
procesadores accedan a los datos por CPU podran incluso no llegar a necesitarse bloqueos
para nada. De hecho, un buen programador debe asegurarse de que cada procesador accede
solo a sus datos. Pero esto solo son consejos, y no hay restricciones sobre el uso de
procesadores en este caso.
En segundo lugar, los datos por CPU reducen la invalidacin de la cach. Esto ocurre
cuando los procesadores intentan mantener sus cachs sincronizadas. Si un procesador
manipula los datos de la cach de otro procesador, ese procesador debe vaciar o actualizar su
cach. Una invalidacin de la cach continuada causa estragos en el rendimiento del sistema.
El uso de datos por CPU reduce al mnimo los efectos negativos de la cach porque los
procesadores normalmente acceden solo a sus propios datos. La interfaz percpu proporciona
la seguridad de que el acceso a los datos de un procesador no afecte a la cach de otros
procesadores.
En consecuencia, el nico requerimento de seguridad para usar los datos por CPU es
deshabilitar la apropiacin del ncleo, cuyo coste es mucho menor que el de bloquear, y
adems es realizado automticamente en las interfaces ya vistas. Tambin este tipo de datos
puede ser utilizado con seguridad en contextos de procesos o interrupciones. La interfaz que
Linux proporciona para el manejo de datos por CPU, en resumen, es muy sencilla de utilizar, y
es susceptible de ser optimizada en el futuro.
12
12.
13.CONCLUSIN
En conclusin, en este trabajo hemos tratado cmo maneja la memoria el ncleo o
kernel del Sistema Operativo Linux. Hemos visto varias unidades de categorizacin de la
memoria, como son los bytes, las pginas o las zonas. Tambin hemos visto diversos
mecanismos para obtener memoria, como los asignadores de pginas o el mecanismo del slab
layer. Obtener memoria en el ncleo no es siempre fcil porque se debe ser cuidadoso con las
condiciones a las que est sometido el ncleo, que deben ser respetadas. Para terminar, queda
claro que la relativa dificultad para hacerse con memoria en el ncleo es una de las mayores
diferencias entre este y el desarrollo en espacios de usuario.
13