Post

Infdev #03 - Memória RAM e Endereços.

Infdev #03 - Memória RAM e Endereços.

Independente da sua área de trabalho ou de estudo, você está lidando com memória, seja manual ou automaticamente. O que importa é que você lida com memória constantemente, e no contexto deste blog, onde C é o maior foco, entender como a memória e os endereços funcionam é crucial para compreender questões que são comumente apontadas como dificuldades ao tentar aprender C, problemas esses que se tornam triviais a partir do momento em que se entende como a memória funciona.

PS: Não irei explicar a nível de hardware sobre flip-flops, endereçamento ou coisas do tipo.

O que é RAM?

RAM significa Random Access Memory, e isso todo mundo sabe, mas a parte do “Random” perde o sentido na hora de traduzir. “Random” vem de “arbitrário”, não de “aleatório”. Não existe acesso aleatório; o que RAM significa é que qualquer local da memória pode ser acessado de forma arbitrária em tempo constante. Sendo assim, é possível salvar e ler valores do meio da RAM tão rapidamente quanto do começo ou do final.

Todo mundo que já estudou sobre memória já ouviu a analogia da rua e das casas: o endereço da sua casa é igual ao endereço na memória, e a sua casa é o valor que está no endereço, ou algo parecido. E essa analogia não está errada, porém eu acredito que seja mais fácil estudar memória pelo que ela realmente é: um grande array.

A definição formal de array é simples: uma lista de tamanho fixo, dividida em elementos de mesmo tamanho, que podem ser acessados a partir de um índice. Isso quer dizer é que um array de inteiros de tamanho 20 só aceitará inteiros, e no máximo 20 elementos. Caso você precise de 21 elementos, crie um novo array, mova os 20 elementos do array antigo para o novo e adicione o novo valor. E, assim como um array, a memória é uma lista de tamanho fixo, dividida em partes de mesmo tamanho, no caso, cada parte possui 1 byte (8 bits). Se você tem 8 GB de RAM, você tem acesso a mais ou menos 64 bilhões de bits, que são 8 bilhões de partes de 8 bits cada. E é possível acessar qualquer valor desses 8 bilhões diretamente pelo índice, no caso da RAM, o índice é o endereço de memória.

Endereços

Um endereço de memória tem o mesmo funcionamento de um índice em um array. Se você salvar um valor no índice 97.812.542, basta salvar o endereço 97.812.542 para usar depois quando precisar do valor salvo. Porém, os endereços são em hexadecimal em vez de decimal (por motivos que não cabem a este post), então o índice 97.812.542 seria o endereço 0x5D4803E (o 0x no começo é uma convenção para indicar hexadecimal, não faz parte do valor). Um endereço de memória não possui um tamanho fixo, porém cada computador possui apenas um tamanho para um endereço, sendo esse o tamanho da word do computador (caso não saiba o que é uma word, eu expliquei no Infdev #01 - C é uma linguagem com problemas, e porquê eles são importantes.). Um computador de 32 bits possui endereços de 32 bits; um de 64 bits possui endereços de 64 bits.

Se você já estudou sobre hardware, talvez saiba que um dos problemas de computadores de 32 bits era que eles eram limitados a 4 GB de RAM, pois o maior endereço que um computador de 32 bits consegue acessar é 0xFFFFFFFF, e FFFFFFFF em hexadecimal equivale a aproximadamente 4.000.000.000 de bytes, que são 4 GB. Enquanto isso, um computador com endereços de até 64 bits consegue acessar teoricamente até 16 exabytes de RAM, o que seria igual a 17 bilhões de GB. Porém, como você sabe, nenhum computador possui tanta memória. Portanto, apenas os endereços que são mapeáveis para a quantidade de memória que o seu computador tem são utilizados; o resto é descartado ou utilizado para alguma coisa específica do sistema operacional.

Vamos para um pequeno exemplo em C:

1
2
3
4
5
6
7
8
9
10
int main() {
    int i = 10;
    int j = 20;    
    int k = 30;

    // & indica que queremos o endereço da variavel, não o valor
    printf("Endereço de i = %p\n", &i);
    printf("Endereço de j = %p\n", &j);
    printf("Endereço de k = %p\n", &k);
}

Neste exemplo, declaramos 3 variáveis: i, j e k. Quando fazemos isso, pedimos ao sistema para reservar um espaço de 4 bytes para cada uma das variáveis (4 bytes porque em C, int em um computador de 64 bits possui o tamanho de 32 bits, ou 4 bytes, isso pode mudar de acordo com a arquitetura da CPU). As linhas seguintes são para mostrar o endereço de memória de cada uma das variáveis.

Podemos ver que i esta em 0x7ffc1b6dc80c, j esta em 0x7ffc1b6dc810, e k esta em 0x7ffc1b6dc814, note que cada endereço esta a 4 bytes de distancia um do outro, pois por cada variável possui 4 bytes, ela vai ocupar 4 valores na memoria. Lembrando que, em hexadecimal, 0x7ffc1b6dc80c + 4 = 0x7ffc1b6dc810, e 0x7ffc1b6dc810 + 4 = 0x7ffc1b6dc814. Caso fôssemos criar mais um valor, ele seria alocado começando em 0x7ffc1b6dc818. Por curiosidade, convertendo esse endereço para decimal, temos que seria o índice 140.720.768.665.616.

Conclusão

A RAM do seu computador é um grande array de valores de 8 bitys, e podemos acessar qualquer um dos valores caso tenhamos os endereços, sejá para salvar ou ler valores. Podemos acessar qualquer valor na memória se tivermos o endereço correto (porém o kernel pode negar caso tente acessar memória protegida). Este post foi bem menor do que os outros, pois decidi fazê-lo para não precisar explicar sobre memória nos próximo post, o qual será sobre ponteiros em C, e onde explicarei algumas coisas importantes sobre aritmética de ponteiros que não são comumente vistas ou discutidas.

This post is licensed under CC BY 4.0 by the author.

Trending Tags