GERENCIAMENTO DE MEMÓRIA NO LINUX 1.INTRODUÇÃO 2.MEMÓRIA FÍSICA 3.MEMÓRIA VIRTUAL 3.1.REGIÕES DA MEMÓRIA VIRTUAL 3.2.TEMPO DE VIDA DO ESPAÇO DE ENDEREÇAMENTO VIRTUAL 3.3.TROCA DE PROCESSOS E PAGINAÇÃO 3.3.1.PAGINAÇÃO 3.3.2.MEMÓRIA 3.3.2.1.DIRETÓRIO DE PÁGINA 3.3.2.2.DIRETÓRIO INTERMEDIÁRIO DE PÁGINA 3.3.2.3.TABELA DE PÁGINA 3.3.3.SWAPPING 3.3.3.1.TIPOS E ESTRUTURA DE SWAPPING 3.4. MEMÓRIA VIRTUAL DO NÚCLEO 1.INTRODUÇÃO O Linux é um sistema multiprocessos e multiusuários. Então devemos ter um controle rígido sobre a memória para que um processo não sobreponha os recursos (memória) utilizados pelo outro. Ele possui dois sistemas de gerenciamento de memória. O primeiro é o sistema de gerenciamento de memória física. Ele cuida da alocação e liberação de blocos de memória. O segundo é o sistema de gerenciamento de memória virtual. Este tem o papel de "enganar" os processos dizendo que há memória suficiente quando não há. Esta técnica pode melhorar a performance do sistema operacional. A seguir veremos algumas estratégias usadas pelos dois componentes para aumentar a performance do processamento. 2.MEMÓRIA FÍSICA O administrador de memória física principal no Linux é o alocador de páginas. Esse processo é responsável por alocar e liberar páginas físicas, sendo capaz de alocar grupos de páginas contíguas. O alocador de páginas usa um algoritmo de alocação de regiões vizinhas, que combina unidades de alocação adjacentes em uma única unidade. Cada região de memória que pode ser alocada possui uma região adjacente correspondente, ou vizinha. Sempre que duas regiões vizinhas são liberadas, elas são combinadas para formar uma região maior. Essa região maior também tem uma vizinha, com a qual pode ser combinada para formar uma região livre ainda maior. Como alternativa, quando não existir uma região de memória disponível pequena para satisfazer a uma requisição de uma pequena porção de memória, uma região maior de memória é subdividida em duas vizinhas. O sistema utiliza listas ligadas para áreas disponíveis de cada tamanho permitido. No Linux, o menor tamanho de área que pode ser alocada usando esse mecanismo corresponde ao de uma única página física. As alocações de memória no núcleo do Linux ocorrem estaticamente, por rotinas de controle que reservam uma área contígua de memória no momento da carga do sistema, ou dinamicamente, pelo controlador de páginas. Entretanto, as funções do núcleo não precisam usar o alocador de páginas para reservar memória. Existem vários outros subsistemas de gerenciamento de memória especializados, que usam o controlador de páginas subjacente para gerenciar seu próprio espaço de memória. Os subsistemas de memória mais importantes são o sistema de memória virtual, o sistema de alocação de áreas de memória de tamanho variável, kmalloc, e o sistema de alocação de espaço nas duas memórias cache de dados persistentes do núcleo: a memória cache de áreas de armazenamento temporário e a memória cache de páginas. Muitos componentes do Linux precisam alocar espaço a páginas inteiras, mas freqüentemente pode ser necessário alocar blocos menores de memória. O núcleo oferece um subsistema adicional para a alocação de áreas de memória de tamanho variável, sem tamanho previamente definido, podendo ser de apenas alguns bytes, em vez de uma página inteira. Esse serviço, fornecido pela rotina kmalloc, análoga á rotina malloc da linguagem C, aloca blocos a páginas inteiras, sob demanda, mas subdivide esses blocos em partes menores. O núcleo armazena dados sobre os blocos em uso pelo sistema kmalloc, em listas que contêm, cada uma, apenas blocos que foram subdivididos em partes de um tamanho especifico. A alocação de memória envolve selecionar a lista apropriada e retirar a primeira área disponível dessa lista, ou alocar espaço a uma página e subdividi-lo. Tanto o controlador de páginas, quanto o kmalloc, não podem ser interrompidos. Uma rotina que deseje alocar uma área de memória informa a prioridade da sua requisição à rotina de alocação. Rotinas de interrupção utilizam uma prioridade atômica, que garante que a requisição seja satisfeita ou que falhe imediatamente, caso não exista mais memória disponível. Em contraposição, para uma requisição de memória de um processo comum de usuário, uma área de memória livre é procurada, sendo o processo bloqueado até que uma área de memória se torne disponível. A prioridade de alocação também pode ser usada para especificar a requisição de memória de acesso direto (DMA). Esse recurso é usado em algumas arquiteturas, como em PCs, onde certas requisições de DMA não podem ser realizadas sobre qualquer bloco da memória física. As regiões de memória solicitadas pelo sistema kmalloc ficam alocadas até que sejam explicitamente liberadas. O sistema kmalloc não pode transferir essas regiões de uma posição para outra ou liberá-las em resposta a uma diminuição do espaço livre em memória. Os outros três subsistemas principais de memória que realizam um gerenciamento próprio de blocos de memória física são fortemente relacionados entre si. Esses sistemas gerenciam o uso da memória cache de áreas de armazenamento temporário, da memória cache de páginas e da memória virtual. A memória cache de áreas de armazenamento temporário é a principal memória cache do núcleo para dispositivos de E/S baseada em blocos; além disso constitui o principal mecanismo por meio do qual as operações de E/S sobre esses dispositivos são realizadas. A memória cache de páginas armazena páginas inteiras de dados de arquivos e não é restrita apenas aos dispositivos que fazem E/S usando blocos. Ela também pode ser usada para armazenar dados transmitidos por meio da rede e é utilizada tanto pelos sistemas de arquivos originais do Linux, que usam discos, quanto pelo sistema de arquivos de rede NES. O sistema de memória virtual gerencia o espaço de endereçamento de cada processo. Esses três sistemas de memória interagem entre si. A leitura de uma página de dados para a memória cache de páginas usa a memória cache de áreas de armazenamento temporário. As páginas da memória cache de páginas podem também usar o sistema de memória virtual, caso um processo tenha mapeado o arquivo correspondente no seu espaço de endereçamento. O núcleo usa um contador de referências a cada página na memória física para que as páginas compartilhadas por dois ou mais desses subsistemas possam ser liberadas, quando elas não estiverem mais sendo usadas em nenhum deles. 3.MEMÓRIA VIRTUAL O sistema de memória virtual do Linux é responsável pelo uso do espaço de endereçamento de cada processo. Esse sistema aloca espaço de memória virtual sob demanda e gerencia a transferência de páginas entre o disco e a memória, quando necessário. No Linux, o administrador de memória virtual usa duas visões do espaço de endereçamento de um processo: como um conjunto de regiões separadas e como um conjunto de páginas. A primeira dessas visões do espaço de endereçamento é a visão lógica, que descreve as instruções recebidas pelo sistema de memória virtual relativas á organização do espaço de endereçamento. Nessa visão, o espaço de endereçamento consiste em regiões separadas, cada qual consistindo em um espaço contíguo de páginas. Essa região é descrita, internamente, por uma única estrutura vrn_area_struct, que define as propriedades dessa região, incluindo os direitos de acesso do processo para realizar operações de leitura, escrita e execução nessa região, assim como dados relativos aos arquivos associados á região. As regiões de cada espaço de endereçamento são organizadas em uma árvore binária balanceada, para possibilitar uma pesquisa eficiente por uma região correspondente a um endereço virtual. O núcleo usa uma segunda visão de cada espaço de endereçamento. Essa visão é armazenada nas tabelas de páginas do processo. As entradas nessa tabela de páginas determinam a posição atual de cada página da memória virtual, esteja ela em disco ou na memória física. Essa visão do espaço físico é gerenciada por um conjunto de rotinas, chamadas por tratadores de interrupções de software do núcleo do sistema, sempre que um processo usa uma página que não está presente na tabela de páginas. Cada vrn_area_struct contém um apontador para uma tabela de rotinas que implementam as operações fundamentais de gerenciamento de páginas. Todas as requisições de leitura ou escrita de páginas não disponíveis são eventualmente tratadas por uma rotina apropriada, contida na tabela vrn_area_struct, de forma que as rotinas centrais de gerenciamento de memória não precisam lidar com detalhes específicos de cada tipo de região de memória. 3.1 REGIÕES DA MEMÓRIA VIRTUAL O Linux usa regiões da memória virtual de várias maneiras. Uma região pode ser caracterizada pela memória persistente para onde as páginas dessa região são copiadas ou de onde suas páginas são lidas. A maioria das regiões de memória possui uma cópia reserva em um arquivo ou então não possui cópias reservas. Uma região que não possui cópias reservas constitui o tipo mais simples de memória virtual. Essas regiões representam memórias de demanda zero: quando um processo tenta ler uma página dessa região, ele simplesmente recebe uma página de memória totalmente preenchida com zeros. Uma região com cópia em um arquivo funciona como uma visão de uma seção desse arquivo: sempre que um processo tenta usar uma página dessa região, a tabela de páginas e preenchida com o endereço de uma página da memória cache do núcleo, correspondente ao endereço da página requerida do arquivo. A mesma página de memória física é usada tanto pela memória cache de páginas quanto pelas tabelas de páginas do processo, de modo que qualquer alteração feita sobre o arquivo, pelo sistema de arquivos, é imediatamente visível a qualquer processo que tenha essa página mapeada em seu espaço de endereçamento virtual. Vários processos podem mapear, em seu espaço de endereçamento, uma mesma região de um determinado arquivo, resultando na utilização da mesma página de memória física por todos esses processos. Uma região de memória virtual é também definida pela forma como são tratadas as operações de escrita sobre essa região. O mapeamento de uma região no espaço de endereçamento de um processo pode ser privado ou compartilhado. Se um processo escreve em uma região privada, o controlador de páginas detecta que é necessária uma cópia-em-escrita, para manter essas atualizações locais ao processo. Por outro lado, uma operação de escrita sobre uma região compartilhada resulta na atualização da cópia dessa região mantida na memória, de modo que essa atualização seja imediatamente visível a todos os processos que usam essa região. 3.2 TEMPO DE VIDA DO ESPAÇO DE ENDEREÇAMENTO VIRTUAL Existem exatamente duas situações em que o núcleo do sistema cria um novo espaço de endereçamento virtual: quando um processo executa um novo programa, por meio de uma chamada à rotina do sistema exec, ou na criação de um novo processo, por meio da rotina de sistema fork. O primeiro caso é fácil: quando um novo programa vai ser executado, o processo recebe um novo espaço de endereçamento virtual, completamente vazio. É responsabilidade das rotinas do sistema carregar o programa, preenchendo o espaço de endereçamento com regiões da memória virtual. No segundo caso, a criação de um novo processo pela rotina fork envolve a criação de uma cópia completa do espaço de endereçamento virtual do processo existente. O núcleo do sistema copia os descritores vrn_area_struct do processo pai e cria um novo conjunto de tabelas de páginas para o processo filho. As tabelas de páginas do processo pai são diretamente copiadas nas tabelas do processo filho, incrementando o contador de referências de cada página. Portanto, após uma chamada á rotina fork, o processo pai e o processo filho compartilham as mesmas páginas físicas de memória em seus espaços de endereçamento. Um caso especial ocorre quando essa operação de cópia envolve uma região privada da memória. Qualquer página que tenha sido escrita pelo processo pai nessa região é uma página privada, e as alterações subseqüentes dessa página, sejam pelo processo pai, ou pelo processo filho, não devem ser refletidas na página do espaço de endereçamento do outro processo. Quando as entradas da tabela de páginas correspondentes a essas páginas são copiadas, elas são reservadas apenas para leitura e marcadas como páginas de cópia-em-escrita. Se essas páginas nunca forem modificadas por qualquer um dos processos, ambos continuam compartilhando a mesma página de memória física. Entretanto, se qualquer um dos processos tentar modificar uma página marcada como página de cópia-em-escrita, o contador de referências dessa página será verificado. Se a página ainda continuar compartilhada, o processo copiará seu conteúdo para uma nova página de memória física e usará essa nova cópia. Esse mecanismo assegura que páginas de dados privados sejam compartilhadas entre processos sempre que possível: serão feitas cópias somente quando for absolutamente necessário. 3.3 TROCA DE PROCESSOS E PAGINAÇÃO Uma tarefa importante do sistema de memória virtual é a transferência de páginas, da memória física para o disco, quando necessário. Os primeiros sistemas UNIX transferiam todos os dados de um processo de uma única vez. Sistemas UNIX mais modernos usam o mecanismo de paginação, que transfere páginas da memória virtual individualmente entre a memória física e o disco. O Linux usa o mecanismo de paginação, em vez de transferir todos os dados de um processo de uma única vez. 3.3.1 Paginação Com a ajuda de tabelas, o sistema operacional mapeia um grande espaço de endereçamento lógico num espaço de endereçamento físico menor. Quando os processos precisam de mais memória principal do que está fisicamente presente, segmentos individuais de memória lógica que não foram referenciados recentemente são realocados no Disco Rígido. Quando um programa acessa um endereço lógico que está atualmente localizado no Disco Rígido, o respectivo segmento de memória (chamado página) é carregado na memória principal, enquanto outro segmento de memória precisa ser escrito para o Disco Rígido para compensar. Devido ao tempo de acesso do Disco Rígido ser significativamente mais alto se comparado com a memória principal, há naturalmente um preço a ser pago em termos de velocidade de execução. A fim de ser capaz de usar o Disco Rígido para o gerenciamento de memória virtual e a memória principal lógica, swap files (arquivos de troca) ou swap partitions (partições de troca) devem ser criados no Disco Rígido. Sem tais partições ou arquivos, a memória principal é limitada ao seu tamanho físico disponível realmente. O sistema de paginação pode ser dividido em duas partes. A primeira consiste no algoritmo que define a política de substituição de páginas, que escolhe a página que vai ser copiada da memória para o disco e determina quando essa página deve ser copiada. A segunda consiste no mecanismo de paginação, que realiza a transferência dos dados entre a memória e o disco, quando necessário. A política de substituição de páginas do Linux usa uma versão modificada do algoritmo do relógio (ou de segunda chance). O Linux usa um relógio de vários passos e cada página tem uma idade, ajustada a cada passo do relógio. Mais precisamente, a idade é uma medida da juventude da página, isto é, de quantas vezes a página foi usada recentemente. As páginas freqüentemente usadas terão idade maior e a idade de uma página pouco usada vai caindo gradualmente, a cada passo do relógio, até atingir o valor zero. Essa informação sobre a idade das páginas permite que o algoritmo de substituição selecione uma página com base na política MRU. O mecanismo de paginação oferece suporte ao gerenciamento de páginas, tanto para dispositivos e partições dedicados à troca de processos, como para arquivos comuns, embora a troca de páginas de arquivos comuns seja substancialmente mais lenta, em razão da sobrecarga extra, devida ao sistema de arquivos. Os blocos são alocados a partir dos dispositivos de troca, de acordo com uma tabela de blocos em uso, que é armazenada na memória principal. O processo que faz a alocação usa um algoritmo que escolhe a próxima área de tamanho suficiente para armazenar os dados requeridos, tentando escrever as páginas em blocos contíguos do disco, para obter melhor desempenho. Para registrar a informação de que uma página foi escrita de volta no disco, esse processo usa uma técnica disponível nas tabelas de páginas de processadores modernos: ele liga o bit de página não presente da entrada correspondente à página na tabela de páginas, possibilitando que o restante dessa entrada seja preenchido com o endereço onde a página foi escrita no disco. 3.3.2 Memória Os níveis do cache são inicializados pela BIOS e portanto, tornam-se transparentes à programação. Por essa razão, os níveis do cache não são mapeados pelo modelo de memória de arquitetura independente e o termo memória física em geral é usada para se referir à RAM. A memória física é dividida em páginas, na qual é definida no arquivo "asm/page.h" com tamanho de 4 KB para processadores x86 e 8 KB para processadores Alpha. A conversão do endereço da memória linear para o endereço da memória física é feita pelo processador ou pela MMU (Memory Management Unit). Esta conversão é feita em 3 níveis, na qual o endereço linear é dividido em 4 partes. A primeira parte é usada como um índice no diretório de página (page directory) e sua entrada faz referência ao diretório intermediário de página (page middle directory). A segunda parte é usada como índice do diretório intermediário de páginas, que por sua vez, faz referência à Tabela de Páginas (page table). A terceira parte é um índice da Tabela de Página, que aponta (se possível) para uma página na memória física. Finalmente, a quarta parte do endereço fornece o deslocamento dentro da página de memória física selecionada. Os processadores x86 suportam apenas conversões em dois níveis. Neste caso, o tamanho do diretório de página intermediária (pmd) é definida como um e a entrada do diretório de página (pgd) passa a ser interpretada como um diretório de página intermediária (pmd). Entretanto, a conversão do endereço linear deve ser dado em 3 níveis (segundo a definição do modelo de memória de arquitetura independente). Como consequência, há um aumento da pgd e da tabela de página. 3.3.2.1 Diretório de Página (Page Directory) As definições de como tipos de dados, funções e macros acessam e modificam páginas da tabela ou diretório estão nos arquivos "asm/page.h" e "asm/pgtable.h". As entradas do diretório de página são dados do tipo pgd_t, que é definida como estrutura e acessado pelo método pgd_val(). Os métodos que devem ser selecionados quando o arquivo "asm/pgtable.h" é compilado são: pgd_alloc() pgd_bad() pgd_clear() pgd_free() pgd_inuse() pgd_none() pgd_offset() pgd_page() Aloca uma página para o diretório de páginas e preenche-a com zero Pode ser usado para testar se a entrada no diretório de página é válida Apaga a entrada no diretório de páginas Libera a página de memória alocada para o diretório de páginas Confere se o diretório de páginas está sendo usado por algum processo Testa se a entrada foi inicializada Retorna o ponteiro para a entrada no diretório de páginas de um endereço linear O endereço da página a qual a entrada no diretório de página se refere - usualmente o endereço base de um diretório intermediário de página. Na arquitetura X86 esta função retorna o endereço base de uma tabela de páginas se THREE_LEVEL não é setada pgd_present() Mostra se a entrada no diretório de página se refere a um diretório intermediário de páginas. Na arquitetura X86, se a macro THREE_LEVEL não estiver definida, esta função testa se o diretório de páginas se refere a uma tabela de páginas pgd_reuse() O contador de uso do diretório de páginas é incrementado em um pgd_set() A entrada no diretório de páginas é setada para o endereço base de um diretório intermediário de páginas. Na arquitetura X86, se a macro THREE_LEVEL não estiver definida, esta função é programada para setar o endereço base de uma tabela de páginas SET_PAGE_DIR() Esta macro/função reseta o endereço base do diretório de páginas para uma tarefa 3.3.2.2 Diretório Intermediário de Página (Page Middle Directory) As entradas do diretório intermediário de página são dados do tipo pmd_t e o acesso é feito pelo método pmd_val(). As funções abaixo são definidas: pmd_alloc() Aloca um diretório intermediário de página na área do usuário pmd_alloc_kernel() Aloca um diretório intermediário de página para a memória no segmento do kernel. Todos os dados são setados para inválidos pmd_bad() Testa a validade do diretório intermediária de página pmd_clear() Deleta a entrada do diretório intermediário de página pmd_free() Libera a entrada da diretório intermediário de página pmd_free_kernel() Libera um diretório intermediário de página da memória do segmento de kernel pmd_inuse() Testa se o diretório intermediário de página está sendo usado por um ou mais processos pmd_none() Testa se o diretório intermediário de página foi setado pmd_offset() Retorna o endereço de uma entrada no diretório intermediário de página, na qual o endereço no argumento é alocado: a entrada do diretório correto deve ser passado como parâmetro pmd_page() Retorna o endereço base de uma tabela de página para o qual a entrada se refere pmd_present() Testa a presença de uma tabela de página referente a entrada no diretório intermediário de página pmd_set() pmd_reuse() Seta a entrada no diretório intermediário de página para a base de endereço de uma tabela de página (não é definido para arquitetura x86) Incrementa o contador para os processos usando o diretório intermediário de página referenciado por parâmetro 3.3.2.3 Tabela de Página (Page Table) Uma entrada na tabela de páginas é definida pelo tipo de dados pte_t. Como antes, há uma macro pte_val(), que fornece acesso ao valor do tipo de dados. Uma entrada na tabela de páginas define um número de atributos para a página de memória referenciada. Estes começam com um número de atributos de proteção de memória, permitindo que a página seja lida, escrita e executada. Além disso, existem os atributos 'copy-on-write', 'dirty' e 'age'. Há outros atributos como estes, mas estes não podem ser modificados individualmente pela funções fornecidas no modelo de memória de arquitetura independente. Portanto, as seguintes combinações de atributos são definidas como macros do tipo pgprot_t : PAGE_NONE PAGE_SHARED PAGE_COPY PAGE_READONLY PAGE_KERNEL Nenhuma página da memória é referenciada pela entrada na tabela de páginas Esta página de memória pode ser referenciada por um número de processos. Todos os tipos de acesso são permitidos Esta página de memória pode ser referenciada por um número de processos. O atributo 'copy-on-write' é setado É permitido somente acesso de leitura ou execução para esta página de memória Acesso a esta página de memória é permitido somente no segmento do kernel Uma série de funções foram definidas para manipular as entradas na tabela de páginas e seus atributos. Note que as funções são descritas aqui pela referência a atributos explicados acima. Para arquiteturas que não suportam todos os atributos para páginas definidas no modelo de memória de arquitetura independente, os significados podem variar. mk_pte() Retorna uma entrada na tabela de páginas gerada do endereço de memória de uma página e uma variável do tipo pgprot_t, que descreve a proteção de memória para a página pte_alloc() Aloca uma nova tabela de páginas pte_alloc_kernel() Aloca uma nova tabela de páginas para a memória no segmento do kernel pte_clear() Limpa a entrada na tabela de páginas pte_cow() pte_dirty() pte_exec() pte_exprotect() pte_free() pte_free_kernel() pte_inuse() pte_mkclean() pte_mkcow() pte_mkdirty() pte_mkexec() pte_mkold() pte_mkread() pte_mkwrite() pte_mkyoung() pte_modify() pte_none() pte_offset() pte_page() pte_present() pte_rdprotect() pte_read() pte_reuse() Verifica a entrada na tabela de páginas para ver se o atributo 'copy-on-write' está setado Verifica se o atributo 'dirty' está setado Verifica se a execução de código na página de memória referenciada é permitida, isto é, se o atributo 'execute' está setado Limpa o atributo 'execute' Libera a tabela de páginas Libera a tabela de páginas responsável por gerenciar as páginas no segmento do kernel Verifica se a tabela de páginas está sendo referenciada por quaisquer processos Limpa o atributo 'dirty' Seta o atributo 'copy-on-write' para a página de memória referenciada Seta o atributo 'dirty' Seta o atributo 'execute', código de permissão na página a ser executada Seta o atributo 'age' Seta o atributo 'read' para conceder acesso à leitura para a página Seta o atributo 'write' para conceder acesso à leitura para a página Limpa o atributo 'age' O atributo de proteção para a página de memória referenciada pela entrada na tabela de páginas é modificada conforme definido no parâmetro Verifica se a entrada na tabela de páginas está setada Retorna um ponteiro para a entrada na tabela de páginas referenciando a página de memória à qual o endereço passado como um parâmetro faz referência. Portanto, o parâmetro passado deve ser a entrada no diretório intermediário de páginas válida para esta página Retorna o endereço da página referenciada pela entrada na tabela de páginas Verifica se uma página na memória física é referenciada pela entrada na tabela de páginas Limpa o atributo 'read' para proteger a página referenciada pela entrada na tabela de páginas contra acessos de leitura Verifica se o atributo 'read' está setado Incrementa de 1 o contador para o número de processos usando esta tabela de páginas pte_uncow() pte_write() pte_wrprotect() pte_young() Limpa copy-on-write para a página referenciada Verifica a autorização de escrita para a página referenciada testando o atributo 'write' Seta o atributo 'write' para ativar a proteção de escrita para a página referenciada Verifica que o atributo 'age' não está setado 3.3.3 Swapping É uma operação realizada pelo Sistema Operacional quando há a necessidade de um processo trazer uma página virtual para a memória física e não há páginas físicas livres disponíveis. Neste caso, o Sistema Operacional prioriza esta página, descartando outra página de memória física. Se a página a ser descartada da memória física veio de arquivo de uma imagem ou de dados e não foi escrita para a página então, ela não precisa ser gravada. Ao invés disso, pode ser descartada e se o processo precisar daquela página novamente, ela pode ser trazida de volta do arquivo de imagem ou de dados para a memória. Portanto, se a página foi modificada, o Sistema Operacional deve preservar o conteúdo de cada página a fim de que possam ser acessadas posteriormente. Este tipo de página é conhecida como uma dirty page e quando é removida da memória, ela é gravada num grupo especial de arquivos chamado swap file (arquivo de troca). Acessos ao swap file são muito grandes em relação à velocidade do processador e à memória física e o Sistema Operacional deve atender à necessidade de escrever páginas para o disco com a necessidade de conservá-las na memória para serem usadas novamente. Se o algoritmo decide quais páginas descartar ou trocar (o algoritmo de swap (troca) não é eficiente) então uma condição conhecida como thrashing ocorre. Neste caso, as páginas estão constantemente sendo escritas para o disco e estão sendo lidas de volta e o Sistema Operacional está ocupado demais para permitir que muito trabalho real seja realizado. Se, por exemplo, o quadro de página física número 1 está sendo regularmente acessado então ele não é um bom candidato para o swapping para o Disco Rígido. O conjunto de páginas que um processo está atualmente usando é chamado de working set (conjunto de trabalho). Um esquema de swap eficiente teria certeza de que todos os processos têm seu conjunto de trabalho na memória física. O Linux usa uma técnica chamada página LRU (Least Recently Used - Menos Usada Recentemente) que permite escolher páginas que podem ser removidas do sistema. Este esquema envolve cada página no sistema tendo uma idade que muda quando a página é acessada. Quanto mais a página é acessada, mais nova ela é; quanto menos ela é acessada, mais antiga e mais passada ela se torna. Páginas antigas são boas candidatas para o swapping. 3.3.3.1 Tipos e Estrutura de Swapping O Linux executa o swapping de duas formas. Na primeira, o chamado dispositivo de swap, usa-se um bloco completo de um dispositivo como arquivo de swap, uma partição do Disco Rígido. Na segunda, o chamado arquivo de swap, usa-se arquivos de tamanho fixo. Para facilitar, será usado o termo espaço de swap para referência dos dispositivos de swap e arquivos de swap. Existe uma estrutura definida para espaço de swap. Os primeiros 4096 bytes contém um mapa de bits. Os bits setados indicam que a página de memória está disponível para paginação. O número do espaço de swap contido nos bits setados corresponde ao deslocamento de bits a partir do início do espaço. Do byte 4086 em diante é armazenado uma string de caracteres "SWAP_SPACE" como um identificador. Isso significa que apenas 4086 x 8 - 1 páginas de memória (130784 KB) podem ser gerenciados no espaço de swap. O Linux permite, além disso, administrar 8 espaços de swap em paralelo, conforme especificado em MAX_SWAPFILES; mas este valor pode ser acrescido para 64. A vantagem de se usar dispositivos de swap ao invés de arquivos de swap é que a página é sempre salva em blocos consecutivos. Em arquivos de swap, uma página pode ser salva em vários blocos não contíguos dependendo de como o sistema de arquivo fragmentou o arquivo quando ele foi criado. Estes blocos então precisam ser encontrados por meio do inode do arquivo de swap. Num dispositivo de swap, o primeiro bloco é dado diretamente pelo deslocamento para a página de memória a ser gravada ou lida. O restante então segue este primeiro bloco. Quando um dispositivo de swap é usado, somente um pedido de leitura ou escrita é feito para cada página, enquanto um arquivo de swap pede um número dependendo da proporção entre o tamanho de página e o tamanho do bloco. Num caso típico (quando um tamanho de bloco de 1024 bytes é usado) isto é agrupado em quatro pedidos separados, para áreas de leitura no meio externo que pode não necessariamente seguir um após o outro. No Disco Rígido, isto causa movimentos da cabeça de leitura/escrita, o que afeta a velocidade de acesso. A chamada de sistema swapon loga num dispositivo de swap ou arquivo para o kernel. int sys_swapon(const char * special_file); 3.4 MEMÓRIA VIRTUAL DO NÚCLEO O Linux reserva, para seu próprio uso, uma região do espaço de endereçamento virtual de cada processo, de tamanho constante e independente do processador. As entradas da tabela de páginas correspondentes a essas páginas do núcleo são marcadas como protegidas, para que essas páginas não sejam visíveis ou modificáveis, para processos que estejam sendo executados em modo usuário. Essa área de memória virtual do núcleo contém duas regiões. A primeira região é uma área estática, que contém as referências da tabela de páginas e é utilizada para facilitar a tradução de endereços físicos em endereços virtuais, quando o núcleo está sendo executado. A parte central do núcleo, juntamente com todas as páginas alocadas pelo alocador de páginas, residem nessa área. O restante da seção reservada ao núcleo, no espaço de endereçamento virtual de um processo, não é destinado a nenhum propósito específico. As entradas na tabela de páginas correspondentes a essa faixa de endereços podem ser modificadas pelo núcleo, se desejado, de modo a apontar para outras áreas de memória. O núcleo oferece duas rotinas que possibilitam a um processo usar essa memória virtual. A rotina vmalloc aloca um número arbitrário de páginas de memória física e associa essas páginas a uma única região da memória virtual do núcleo, possibilitando a alocação de uma grande área de memória contígua, mesmo que não exista um número suficiente de páginas de memória física contíguas para satisfazer a requisição. A rotina vremap associa uma seqüência de endereços de memória virtual a uma área de memória usada por um controlador de dispositivo, para ser usada para E/S mapeada em memória.