Gerência de Memória
Autor: Hermano | Publicado: 2013-11-21T05:06:00-08:00




A gerência da memória do FESO funciona em diversos níveis. No
nível mais baixo, existe a gerência da memória física, no qual é feito o
controle de quais blocos da memória estão disponíveis para a alocação. Sobre a
gerência da memória física, existe o controle da memória virtual, responsável
por mapear os endereços dos frames
(quadros) de memória física, em endereços virtuais. E ainda acima desta,
existem os algoritmos de alocação de memória, que se utilizam de uma chamada ao
sistema para solicitar mais memória ao SO, e controlam blocos de memória de
tamanhos arbitrários. Esta seção trata do funcionamento de cada um desses
níveis.



Gerência de Memória Física


A gerência de memória física funciona da seguinte maneira: após
o processo de inicialização do sistema, uma área de memória, localizada após a
imagem do sistema operacional é reservada. Está área, cujo tamanho depende do
tamanho da memória real instalada no sistema, é utilizada para armazenar um
mapa de bits utilizado no controle da
memória física. Cada bit no mapa
representa uma área de memória de 4KB como ilustra a figura abaixo. Caso o estado do
bit em uma determinada posição esteja em 1, o frame está ocupado, caso o
bit esteja em 0, o frame está
vazio. 



A memória disponível
para utilização começa na primeira posição alinhada em 4KB após o mapa de bits. Isto porque, o uso da paginação
nos processadores da família Intel requer endereços alinhados em 4KB, ou seja,
com os 12 bits menos significativos
iguais a 0. Como cada bloco tem 4KB, todos eles começam em um endereço de
memória alinhado em 4KB. Sempre que é necessária a alocação de mais memória,
ocorre uma busca no mapa de bits
iniciada geralmente pelo último endereço retornado pelo alocador. A busca é
feita usando um algoritmo first-fit,
de maneira que o endereço do primeiro conjunto de blocos contíguos do tamanho solicitado
ao alocador é retornado. É possível saber o endereço inicial do frame com base na posição do bit dentro do mapa.





Gerência de Memória Virtual



Em outro nível, a utilização da memória virtual permite a criação
de um espaço de endereçamento virtual composto por um conjunto de endereços
virtuais. Esses endereços virtuais são mapeados em endereços físicos, de forma
a dar a impressão aos programas de usuário que eles possuem toda a memória da
máquina apenas para eles.



O loader do sistema
FESO é muito simples, e não suporta a relocação de programas. Entretanto, a
utilização de espaços de endereçamento virtuais permite que diversos programas
utilizem o mesmo conjunto de endereços virtuais, que são mapeados em frames de memória física distintos para
cada um deles. Como existe um espaço de endereçamento personalizado para cada
aplicativo de usuário ou driver de
dispositivo, não é preciso realizar a relocação dos endereços para fazer com
que todos esses aplicativos ou drivers
possam coexistir na memória.&nbsp; 



O
espaço de endereçamento virtual nos processadores da família Intel de 32 bits é
de 232, ou seja, 4 GB. O kernel fica mapeado da mesma forma nos
endereços do último gigabyte de todos
os espaços de endereçamento. Isto é necessário, pois as rotinas do kernel devem estar sempre acessíveis,
não importando qual programa está em execução.&nbsp;
Resta a cada programa de usuário um espaço de endereçamento de 3GB.



À
medida que programas de usuário (que ocupam quantidades diferentes de memória e
são geralmente carregados em posições adjacentes) são iniciados e finalizados,
surgem na memória áreas fragmentadas, que podem dificultar o carregamento de
novos programas maiores. Este problema é conhecido como fragmentação externa, e
também é resolvido com o uso da paginação. Uma vez que a paginação permite que frames não contíguos de memória física
possam ser mapeados em páginas contiguas no espaço de memória virtual, não
importa em quais frames de memória física os programas são carregados, pois,
eles são mapeados em páginas virtuais adjacentes.







Nos
processadores da família Intel o mapeamento de endereços virtuais em físicos é
feito através do uso de dois níveis de tabelas de páginas, como demonstra a
figura acima. No primeiro nível existe a Page
Directory, que possui 1024 entradas. Cada uma dessas entradas aponta para
uma Page Table. As Page Tables, por sua vez, também possuem
1024 entradas, e cada uma delas aponta para um bloco de 4KB de memória física.
Dessa forma, o mapeamento de endereços virtuais em físicos é feito da seguinte
forma: os 10 primeiros bits mais
significativos do endereço virtuais de 32 bits
representam um índice na Page Directory.
Os 10 bits anteriores a estes
representam um índice na page table,
e os 12 bits menos significativos
representam o deslocamento dentro do frame
de memória.



Uma limitação da
gerência de memória do sistema FESO é a não utilização de técnicas para troca
entre programas, ou partes de programas, da memória para alguma forma de
armazenamento secundário ou vice-versa. Caso não haja memória física disponível
para um programa, este simplesmente não é executado pelo sistema.


Alocação de Memória


Diversos programas de computador são criados de maneira que a
quantidade total de memória necessária em sua execução não é definida durante
seu desenvolvimento. Isto é, não há como saber exatamente quanta memória o
programa irá precisar, ou mesmo a quantidade de memória pode variar a cada
execução.

Neste caso, os programas se utilizam da alocação dinâmica de
memória, que consiste na expansão da memória utilizada por um programa na
medida em que esta é necessária. O sistema operacional deve controlar quanta
memória cada programa está utilizando, e permitir que mais memória seja alocada
durante sua execução.



A alocação dinâmica é utilizada tanto pelo núcleo e drivers de dispositivos, quanto pelos
aplicativos de usuário. Cada programa possui uma área reservada em seu espaço
de endereços para a alocação dinâmica. Está área está é conhecido como heap e está também presente no espaço de
endereçamento do núcleo.

Na linguagem C, as funções malloc
e free são as principais responsáveis pela alocação e liberação de blocos
de memória. O sistema operacional oferece uma estrutura base na qual essas
funções podem operar. Cada processo, assim como o kernel, possui variáveis para o controle do heap. Sempre que a função malloc
(ou sua versão implementada dentro do kernel,
a kmalloc) necessita de mais memória,
é preciso aumentar o heap, e retornar
o endereço do primeiro byte de
memória da área recém-expandida.



No caso do kernel, as
rotinas da gerência de memória virtual alocam um novo bloco de memória física e
aumentam a área do heap. Os
programas, por sua vez, fazem uma chamada ao sistema operacional, solicitando
uma nova área de memória. Cada processo de usuário possui suas próprias
variáveis para controle de quanta memória está sendo utilizada.



A função malloc
utiliza uma lista encadeada com blocos livres de memória como é possível ver na
figura abaixo [1]. Sempre que a função é chamada, a lista é percorrida, e o primeiro
bloco com tamanho igual ou maior ao solicitado que for encontrado é alocado, e
seu endereço é retornado. 






Cada bloco possui em seu começo um pequeno cabeçalho, no qual
existe um ponteiro para o próximo bloco livre, e o tamanho do bloco atual, como
mostra a figura abaixo [1]. Quando parte de um bloco é alocada, este é dividido em
dois, e um novo cabeçalho e criado, com o tamanho do bloco. Este novo bloco não
está ligado à lista encadeada, pois não está livre, porém seu cabeçalho é
criado para que seja possível determinar seu tamanho.



A função free recebe
como parâmetro o endereço inicial do bloco que deve ser liberado. Quando isto
ocorre, a função procura o cabeçalho que deve existir antes do endereço passado
como parâmetro do para saber o tamanho do bloco. Então, a função varre a lista
de blocos livres para saber em que posição da lista encadeada o novo bloco deve
ser colocado. Caso o bloco seja adjacente a outros blocos livres, eles devem
ser unidos em um novo bloco de tamanho maior.



As funções malloc e free funcionam em espaço de usuário.
Desta maneira, a chamada ao sistema para a alocação de mais memória no heap ocorre apenas quando toda a lista
encadeada é percorrida e um nenhum bloco livre de tamanho adequado é encontrado.
Neste caso, o programa solicita um novo bloco de memória ao sistema
operacional, e este é adicionado à lista de blocos livres, gerenciada pela
função malloc.





[1]&nbsp;KERNIGHAN, Brian W; RITCHIE, Dennis M. The C Programming Language. 2. ed. Prentice Hall, 1988.