Mapeamento e Alocação de Memória


 

Modelo usado no Turbo Pascal


A memória é composta de bits que são agrupados de 8 em 8, formando bytes. Cada byte possui um endereço com o qual é possível referenciá-lo. Nas versões mais antigas do Pascal, baseada no DOS, a memória era dividida em segmentos de até 64KB, como mostrado abaixo:

Tanto os dados como o código do programa eram alocados na memória, como mostra a figura abaixo com a organização da memória em um programa:

As variáveis globais, as units (e suas variáveis e rotinas) e o programa principal eram alocados no início da execução. O Heap e a Pilha compartilhavam o resto da memória disponível para o processo.

Para referenciar uma variável era necessário saber seu segmento e o deslocamento (offset) dentro desse segmento. O Pascal tem duas funções chamadas Seg e Ofs que retornam, respectivamente, o segmento e o deslocamento (offset).

Exemplo 1: Imprimir o segmento e o offset de um número inteiro:

var x: integer;
begin
   writeln ('Segmento de X = ', Seg(x));
   writeln('Offset de X = ', Ofs(x))
end.

Era possível acessar diretamente a memória através de arrays especiais:

Mem [<seg>:<ofs>] => cada elemento é um byte

MemW [<seg>:<ofs>] => cada elemento é um word

MemL [<seg>:<ofs>] => cada elemento é um long

Exemplo 2: Mudando o valor do byte contido no segmento $0008, com deslocamento $0050

Mem[$0008:$0050] := 10

 

Exemplo 3: Uma atribuição usando acesso direto à memória

var x, dado: word;
begin
   dado := 0;
   x    := 1;
   dado := MemW[Seg(x):Ofs(x)];
   writeln ('Valor do dado = ', dado);
end.

O endereço de uma variável não mudava durante a execução. O que mudava era o valor armazenado no endereço.

 Podíamos especificar o endereço de uma variável durante sua declaração. Essas variáveis eram chamadas variáveis absolutas.

1º Forma) Especificando o segmento e o offset.

var <nome-variável> : <tipo> absolute <seg>:<offset>;

2º Forma) Especificando outra variável:

var <nome-variável> : <tipo> absolute <nome-da-outra-variável>;

Exemplo 4: Declarando variáveis absolutas

var x : integer absolute $0010:$0005;
    y : integer;
    z : integer absolute y;

 

Exemplo 5: Obter o tamanho de uma string usando uma variável absoluta.

var
   str       : string[100];
   strlength : byte absolute str;
begin
   str := 'string';
   writeln('Tamanho de str = ', strlength);
   strlength := 2;
   writeln(str);    {Escreve apenas st}
end.

 

Modelo usado no Free Pascal no ambiente Windows (e outros)


O Free Pascal utiliza um modelode gerenciamento de memória diferente do usado no Turbo Pascal no ambiente DOS. Neste último, não havia suporte a várias aplicações rodando de forma paralela. Além disso, não havia a possibilidade de usar memória virtual.

O Turbo Pascal, como visto acima, tinha uma quantidade limitada de memória disponível para a aplicação. Já no Free Pascal, a memória que os programas podem utilizar está limitada pela tamanho da memória física e virtual disponíveis, além é claro da alocação de memória feita por outras aplicações que rodam em paralelo.

Desta forma, muitos dos conceitos apresentados acima não fazem mais sentido, como:.

  1. A idéia de que um processo possui uma área de memória fixa dividida em segmentos não procede mais. Logo, não existe mais a divisão em segmentos. Sendo assim, as funções Seg e Ofs retornam, respectivamente, 0 (zero) e o endereço completo de memória. Logo, o tipo de retorno de Ofs deixa de ser word (16 bits) para ser longint (32 bits) ou int64 (64 bits).
  2. Todos os conceitos de Heap e Pilha, exceto que o limite de alocação é a memória física e virtual disponível. O Heap aloca memória do sistema operacional sob demanda, alocando pedaços de 64KBytes, ou 256KBytes ou 1MByte de acordo com o tamanho da variável a ser alocada. O que sobra pode ser usado para alocar as próximas variáveis dinâmicas.

Quando não é possível alocar memória, o Free Pascal pode ter 2 comportamentos:

  1. Gerar o código de erro 203 e encerrar o programa (comportamento padrão).
  2. Fazer com que o procedimento New faça o apontador passado apontar para Nil

O primeiro ocorre quando a variável global ReturnNilIfGrowHeapFails é FALSE (padrão) e o segundo quando é TRUE.