Gerenciamento de Memória no Linux

INSTITUTO TECNOLÓGICO DE AERONÁUTICA
Alunos: Francisco Germano Batista da Silva Júnior e Ricardo Itiro Sabota Tominaga
Professor: Yano
Curso: 2º ano de Computação

Descrição do gerenciamento de memória em Linux.

O gerenciamento da memória no sistema Linux é feito através de memória virtual com paginação para os processos de usuário (através da tabela de paginas e da conversão de um endereço virtual para um endereço físico) e uma correspondência direta dos endereços da memória virtual do Kernel para a memória física.

A memória física é dividida em 3 zonas: ZONE_DMA, ZONE_NORMAL e ZONE_HIGHMEM (alta memória).
ZONE_DMA é utilizada por alguns dispositivos de transferência de dados e é localizada na parte inferior da memória física (até 16MB).
ZONE_NORMAL é a zona que o Kernel tem acesso direto, ocupando um 1GB de espaço. Dessa área 128MB é dedicado a estruturas de dados do Kernel deixando 896MB úteis (1GB-128MB=1024MB-128MB=896MB).
ZONA_HIGHMEM é a zona de memória que está acima de 1GB. O Kernel não trabalha diretamente nessa região da memória física, necessitando trazer o conteúdo da ZONA_HIGHMEM para à ZONA_NORMAL antes de poder tratar o conteúdo da memória.

A memória virtual possui 32 bits de endereçamento, levando à 4G páginas. As páginas que forem dedicadas ao Kernel serão diretamente endereçadas na ZONE_NORMAL, o que nos leva a um tamanho de página de 1Byte. Assim temos 1GB de memória virtual dedicada ao Kernel e 3GB de memória virtual dedicada a processos de usuário. Percebe-se que o atual tamanho da memória virtual é comparavel a memória física (em alguns casos pode ser até menor). Esse fato é recente e se deve ao barateamento da memória física.

A proteção no controle de memória do Linux se da principalmente pelas restrições de controle de acesso à memória (memory access control), informações contidas na PTE (mais informações a seguir).

Tabelas de paginação

A paginação da memória virtual do usuário é feita em 3 níveis. As tabelas são conhecidas como PGD (Page Global Directory, tabela do 1º nível), PMD (Page Middle Directory, tabela de 2º nível) e PTE (Page Table Entry, tabela de 3º nível). A organização das tabelas pode ser visualizada nas segintes figuras:

03fig01.jpg
page-tables.jpg

Cada processo possui uma estrutura de gerenciamento de memória (mm_struct) que possui um ponteiro PGD (mm_struct->pgd). Esse ponteiro para a tabela PGD. A tabela de cada nível possui o número do frame que deve ser usado na tabela do proximo nível. Os valores de "level1", "level2", "level3" e "Byte within page" são utilizados como offset dentro da página para ler a entrada exata da tabela.

Na PTE também fica armazenado informações sobre o controle de acesso à memória, essas informações dependem do processador utilizado. Cada endereço virtual além do PFN (parte do endereço virtual utilizada para o cálculo do endereço físico) possui outras variáveis como mostra o esquema abaixo (exemplo para o Alpha AXP).

pte.jpg

V
Valido, se setado a entrada na tabela de página é valida.

FOE
“Fault on Execute”, Sempre que uma tentativa de executar instruções nessa pagina ocorre, o processador retorna falta e devolve o controle para o sistema operacional,

FOW
“Fault on Write”, Como acima mas a falta ocorreu em uma tentativa de escrita nessa página,

FOR
“Fault on Read”, Como acima mas a falta ocorreu em uma tentativa de leitura nessa página,

ASM
Address Space Match. Esse bit é utilizado quando o sistema operacional deseja deletar algumas entradas do Translation Buffer,

KRE
Código rodando no modo de Kernel possui permissão para ler esta página,

URE
Código rodando no modo de usuário possui permissão para ler esta página,

GH
Granularity hint used when mapping an entire block with a single Translation Buffer entry rather than many,

KWE
Código rodando em modo do Kernel pode escrever nessa página,

UWE
Código rodando em modo do Usuário pode escrever nessa página,
page frame number

Para entradas da tabela de páginas com o bit V setado, este campo contem o endereço físico do page frame (PFN) para essa entrada da tabela de página. Para entrada inválidas, este campo contem informações sobre onde a página está armazenada nos arquivos de SWAPF.

_PAGE_DIRTY
Se ativado, a página precisa ser escrita nos arquivos de swap
_PAGE_ACCESSED
Usado pelo Linux para marcar uma página como acessada.

Como funciona a TLB no Linux

A TLB (Translation Lookaside Buffer) é um dispositivo de hardware utilizado que armazena alguma entradas de endereço virtual de utilização freqüênte. Assim a conversão endereço virtual - endereço real dessas entradas é efetuada mais rapidamente do que se consultas a tabela de páginas fosse necessária. Linux suporta TLBs do tipo R200 e R4000, que são utilizadas pela maioria dos sistemas que podem rodar em Linux. Atualmente Linux suporta somente TLBS com 4kB de tamanho de página, existem planos de opicionalmente incrementar o tamanho da página para 16kB ou 64kB. Segue uma breve descrição dos tipos R2000 e da R4000.

R2000

Esta TLB consiste de 64 entradas. Cada entrada mapeia uma única página cpm tamanho de página de 4kB. A manipulação da TLB é feita por 4 instuções tlbp, tlbr, tlbwi, tlbwr.

R4000

O número de entradas dessa TLB varia de 32 às 64 entradas, sendo 48 o número mais comum de entradas. Cada entrada pode ter um tamanho de página diferente (grande diferença em relação ao tipo R2000), com o tamanho da página variando de 4kB a 16MB. Cada entrada na TLB mapeia um par de páginas adjacentes. A manipulação da TLB é feita pelas instruções tlbp, tlbr, tlbwi, tlbwr.

Interfaces do gerenciamento de memória

Criação de processos

A ciração de processos no Linux é feita através do comando fork(), o processo que cria o novo processo é o processo pai e o processo recem criado é o processo filho. A inicialização do processo pode ser observada no esquema a seguir:

figure1.jpg

Dentro do comando do_fork() a função copymm() é chamado. Essa função destina para o processo filho a região de memória alocada para o processo pai, modificando que as opções de acesso as páginas da memória virtual do processo filho são de leitura e execução. Caso o processo filho necessite escrever na memória ocorre um page fault e uma nova região da memória física será alocada para o processo filho.

Troca de processos

O escalonamento de páginas no Linux é feita pelo algoritmo LRU (Least Recently Used). Nesse tipo de algoritmo as páginas usadas menos recentemente possuem uma maior chance de serem retiradas da memória física caso ocorra uma page fault. A informação sobre a idade do processo é armazenada na estrutura mem_map_t. Essa estrutura serve para armazenar informações sobre o página que está na memória física.

Quando ocorre uma troca de processos o novo processo verifica se a sua página virtual está carregada na TLB. Caso ela não encontre-se lá, a página é procurada na memória virtual. Caso a página requisitada esteja na memória física o endereço virtual é resolvido pelo kernel e o processo ganha acesso ao recurso de memória desejado. Caso a página não esteja na memória virtual será necessário traze-la da área de swap. Neste caso o algoritmo LRU é utilizado e depois desse trabalho adicional do kernel é que o processo ganhará acesso sobre os recursos da memória.

Page fault

Caso ocorra uma page fault o sistema deve identificar se ela é legal ou não. Ele faz isso procurando a estrutura vm_area_structure. Caso ela exista significa que a page fault é legal (executando o comando nopage() da estrutura), caso ela não exista ela é ilegal (o Linux tratará de forma específica essa exceção). Para as falhas legais o sistema deve identificar se a página requisitada está nos arquivos de swap ou em uma unidade de disco. Isso é feito através da entrada na tabela PTE. Se ela estiver vazia significa que a entrada está no disco. Se ela estiver preenchida e invalida, significa que a página encontra-se nos arquivos de swap.

A seguir está um desenho esquemático da estrutura vm_area_structure.

vm_area.gif

Remoção de processos

Um processo pode ser removido (encerrado) sozinho, devido ao fato de ter chegado ao final de sua execução e não ser mais necessário, ou pelo kernel, devido a algum mal funcionamento do processo. A remoção do processo pode ser observada no esquema a seguir:

figure2.gif

A função do_exit() chama a função exit_mm(). Essa última função realiza o swap das páginas da memória física (caso elas estejam lá), adiciona a referência ao espaço liberado na estrutura de memória livre, apaga a referência do processo a PGD e libera as entradas das tabelas de página que estavam sendo utilizadas pelo processo.

Compartilhamento de memória

O compartilhamento de memória é a forma mais eficiente de dois processos (ou threads) compartilharem dados e se comunicarem. Nesse compartilhamento devem ser utilizados mutexes antes da alteração das informações compartilhadas, assim elimina-se condições de corrida crítica.

Criando-se um processo através do comando fork(), conseguimos que o processo pai e filho compartilhem a mesma área de memória.

Cada processo possui a sua própria tabela d enderços virtuais, podendo dois endereços virtuais distintos apontarem para a mesma página ou frame físico.

Mapeamento de arquivos na memória virtual

Sempre que uma imagem executável é executada, o conteúdo dela deve ser trazida ao para o espaço de memória virtual. Cada vez que esse processo é executado ocorre o que é chamado de mapeamento de memória. Cada processo possui uma estrutura de dados chamada mm_struct essa estrutura contém informações sobre a instrução que está sendo executado, e ponteiros para diversas vm_area_struct.
A vm_area_struct descreve as áreas da memória virtual que o processo utiliza, com informações sobre o início e o fim da área de memória virtual utilizada, inodes e etc. Quando ocorre o mapeamento um conjunto de vm_area_structures é criado. Cada vm_area_struct é uma parte da imagem executável. O código executável, as variáveis inicializadas, variaáveis não inicializadas e etc. são carregadas na memória virtual nesse instante.

Referências utilizadas

http://www.ibm.com/developerworks/linux/library/l-linux-process-management/
http://kerneltrap.org/node/2450
http://www.linuxhq.com/guides/TLK/mm/memory.html#tthFrefAAC
http://en.wikipedia.org/wiki/Paging#Linux
http://en.wikipedia.org/wiki/Linux_kernel#cite_note-11
http://www.linux-mips.org/wiki/TLB

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License