Joao Brietzke Blog

← voltar

Como a memória RAM funciona de verdade: do capacitor ao Redis

Todo mundo que mexe com computador sabe que "mais RAM deixa a máquina mais rápida". Mas o que é, de fato, essa memória? Como é que ela guarda um dado? E por que, do nada, uma ferramenta como o Redis tem tudo a ver com isso?


1. O abismo de velocidade: por que a RAM existe

A CPU é absurdamente rápida e faz bilhões de operações por segundo. O disco (o SSD ou HD onde seus arquivos moram) é, em comparação, lentíssimo. Se a CPU tivesse que buscar cada dado direto no disco, passaria a maior parte do tempo parada, esperando.

A RAM existe para preencher esse abismo. Ela é uma memória muito mais rápida que o disco, onde ficam os dados e programas que estão sendo usados naquele momento.

A melhor imagem é uma mesa de trabalho:

  • A CPU é você, o trabalhador.
  • A RAM é a mesa: você coloca nela o que está usando agora. É de fácil alcance, mas tem espaço limitado.
  • O disco é o arquivo/armário: cabe tudo, mas você precisa levantar e ir buscar (lento).

Quando você abre um programa, ele sai do disco e é carregado na RAM. É por isso que um computador com pouca RAM trava quando você abre muitas abas: a mesa fica cheia.

Três características definem a RAM. Ela é volátil (perde tudo quando desliga), é rápida (muito mais que o disco) e é de acesso aleatório: a CPU vai direto a qualquer posição, sem percorrer as anteriores, como pular para uma página de um livro em vez de rebobinar uma fita. Esse último ponto, aliás, é de onde vem o nome: RAM, Random Access Memory.

A ideia geral é uma hierarquia: quanto mais perto da CPU, mais rápido e menor; quanto mais longe, mais lento e maior. A RAM é o equilíbrio do meio.

Hierarquia de memória: CPU, RAM e disco

2. A célula: como um bit é guardado de verdade

Aqui está o coração de tudo. No fundo, um bit é só a resposta para uma pergunta: "tem carga elétrica aqui ou não?". Tem carga = 1, não tem = 0. Toda a memória do seu computador é, literalmente, bilhões dessas perguntinhas.

Na RAM mais comum (a DRAM, aquela dos pentes que você espeta na placa-mãe), cada bit é guardado numa célula feita de apenas duas peças:

  • Um capacitor: pense num baldinho microscópico que segura carga elétrica. Cheio = 1, vazio = 0. É ele que de fato "lembra" o valor.
  • Um transistor: uma chave/torneira que decide quando você pode mexer naquele baldinho.

A divisão de tarefas é simples: o capacitor guarda, o transistor protege e dá acesso. Um não serve sem o outro.

Célula DRAM: transistor e capacitor

Guardar, escrever e ler

Veja o filme completo:

Em repouso, a chave (transistor) está fechada. O capacitor fica isolado, segurando sua carga. O bit está guardado, e ninguém mexe nele. Esse é o estado normal da memória.

Para escrever um 1, abre-se a chave e manda-se carga pela "tubulação" de dados; o baldinho enche. Fecha a chave, e a carga fica presa lá dentro. Para escrever um 0, é o contrário: com a chave aberta, o baldinho esvazia.

Para ler, abre-se a chave e o capacitor despeja sua carguinha; um circuito sensível mede se veio "água" ou não, decidindo se era 1 ou 0. Tem um detalhe curioso aqui: ler esvazia o balde, a leitura é destrutiva. Por isso, logo depois de ler, o circuito regrava o valor de volta para não perder o dado.

Por que ela se chama "Dynamic"

Aquele baldinho tem um problema: ele vaza. O capacitor é tão minúsculo que perde a carga em poucos milissegundos. Sem fazer nada, um 1 viraria 0 sozinho.

A solução é o refresh: um circuito fica o tempo todo lendo cada célula e regravando o valor antes que ele se apague, milhares de vezes por segundo. É esse "re-encher os baldes" constante que dá o nome Dynamic RAM. A memória só se mantém íntegra porque está sendo reescrita sem parar.

E é exatamente daí que vem a volatilidade: sem energia, não há refresh, os baldes se esvaziam e tudo some. Faltou luz e você não tinha salvado o documento? Ele estava só na RAM, que se apagou.

Uma prima mais rápida: a SRAM

Existe outro tipo de memória, a SRAM, que guarda cada bit num arranjo de transistores que se "tranca" no estado 0 ou 1, sem precisar de capacitor nem de refresh. Ela é bem mais rápida, mas ocupa muito mais espaço e custa caro. Por isso a SRAM é usada no cache da CPU (pequeno e veloz), enquanto a DRAM, mais lenta porém barata e densa, forma os gigabytes da memória principal.


3. Do bit ao endereço: o byte

Um bit sozinho é quase inútil: ele só diz 0 ou 1. Para representar algo real (uma letra, um número, uma cor), é preciso combinar vários bits. E quanto mais bits você junta, mais combinações consegue: a cada bit a mais, o número de combinações dobra.

Com 8 bits chega-se a 2⁸ = 256 combinações. Esse foi o tamanho que virou padrão e ganhou nome: o byte. Por que 8? Porque 256 valores bastavam para representar tudo que a computação antiga precisava num pacote só: letras maiúsculas e minúsculas, dígitos, pontuação e símbolos de controle (o famoso ASCII). Grande o bastante para ser útil, pequeno o bastante para ser eficiente.

Um único byte consegue guardar, por exemplo, uma letra (A é o número 65), um número de 0 a 255, ou o quanto de vermelho tem um pixel.

Um byte de 8 bits

Um ponto importante: a memória é endereçável por byte, não por bit. Cada endereço aponta para um byte inteiro. Dar um endereço a cada bit individual exigiria oito vezes mais endereços e muito mais fiação, sem ganho nenhum, afinal você quase nunca precisa de um bit isolado.

Daí pra cima é só escala: cerca de 1.000 bytes formam 1 KB (um parágrafo), 1 MB é um livro inteiro, e um pente moderno de 16 GB guarda dezenas de bilhões dessas casinhas de 1 byte, cada uma com seu endereço.


4. Endereçamento em matriz: como a CPU acha um byte entre bilhões

Bilhões de células não ficam numa fila, o que seria lento de percorrer. Elas são organizadas numa matriz, com linhas e colunas, como as coordenadas de um tabuleiro.

Quando a CPU pede um endereço, esse número é partido em duas metades: uma indica a linha, a outra indica a coluna. Um circuito ativa a fileira certa, outro escolhe a coluna, e o cruzamento aponta para uma célula exata.

Matriz de células de memória

Por que matriz? (a sacada de verdade)

Por que não usar um seletor único e gigante que aponta direto para cada byte? Por causa da fiação.

Um seletor direto precisaria de um fio para cada célula. Numa memória de 1 milhão de células, seriam 1 milhão de fios, o que é inviável. Já uma matriz de 1.000 × 1.000 precisa de apenas 1.000 fios para a linha + 1.000 para a coluna = 2.000 fios para endereçar as mesmas células.

Sair de um milhão de fios para dois mil é a razão de a memória ser uma matriz. Partir o endereço em duas metades é o que torna possível, na prática, ter bilhões de células num chip pequeno.

Uma consequência que afeta performance

Por causa dessa organização, o acesso acontece em duas etapas: primeiro a memória "abre" uma linha inteira de uma vez (deixando-a numa área de apoio rápida), depois escolhe a coluna dentro dela.

O efeito prático é direto: ler dados vizinhos, na mesma linha, é bem mais rápido do que pular para linhas diferentes. É por isso que percorrer dados em sequência costuma ser mais veloz que acessá-los espalhados, algo que influencia o desempenho dos seus programas mais do que parece.

Os nomes técnicos dessas duas etapas, caso você queira pesquisar, são RAS (seleção de linha) e CAS (seleção de coluna).

E isso se repete em camadas, como bonecas russas: uma matriz de células forma um banco; vários bancos por chip; vários chips num rank; e o conjunto montado no pente que você espeta é um módulo. Um endereço real seleciona, em ordem: qual módulo → qual banco → qual linha → qual coluna.


5. Como a CPU sabe onde buscar

Aqui mora um mal-entendido comum. A intuição diz que a CPU "procura" o dado na RAM, vasculhando posições até achar. Não é nada disso.

A CPU já tem o endereço exato na mão antes de pedir. "Saber a localização" não é uma descoberta de última hora: é uma informação que já estava combinada de antemão. O endereço já vem escrito no envelope.

De onde vem esse endereço pronto? De dois lugares.

Primeiro, das próprias instruções do programa. Todo programa é uma sequência de instruções, e a CPU mantém um marcador que aponta para o endereço exato da próxima, e ele simplesmente avança. E quando uma instrução precisa de um dado, ela já traz embutido o endereço dele (ou uma receita para calculá-lo). Uma instrução típica é, literalmente, "carregue o conteúdo do endereço 1000".

Segundo, alguém definiu que era o endereço 1000 muito antes do programa rodar. O compilador, ao traduzir o código, já organiza onde cada coisa vai ficar; o sistema operacional, ao carregar o programa, fixa as posições finais. Quando a CPU executa, ela só segue um mapa que já existia.

Na prática moderna ainda há um passo no meio: o programa usa endereços "virtuais" (uma numeração própria, como se fosse o único dono da memória), e a CPU traduz isso para o endereço físico real na hora. Isso permite que vários programas convivam sem pisar no espaço um do outro.

Jornada de um endereço de memória

Um último detalhe: antes de incomodar a RAM, a CPU confere primeiro o cache (aquela memória ultrarrápida dentro dela, feita de SRAM). Se o dado já estiver lá, nem precisa ir à RAM. Mas, mesmo quando precisa, em nenhum momento houve "busca": a CPU sempre soube exatamente qual número pedir.


6. O padrão se repete: Redis e os caches

Agora a parte que fecha o ciclo. Serviços de cache como o Redis guardam os dados exatamente como estudamos: na RAM. É justamente por viver na memória, e não no disco, que ele é tão rápido, e esse é o motivo de ele ser usado como cache.

Mas, se ele vive na RAM, aquele velho problema volta: a RAM é volátil. Se o servidor reinicia ou falta energia, os dados somem. Para resolver, o Redis oferece persistência opcional em disco: de tempos em tempos ele tira uma "foto" de tudo e salva num arquivo, e/ou anota cada operação num histórico que pode ser reproduzido. Quando liga de novo, ele lê esse arquivo do disco e recarrega tudo para a RAM, e a partir daí trabalha sempre na memória.

Reparou no movimento? É o mesmíssimo trânsito disco → RAM → trabalho → disco que vimos entre o disco e a CPU. O dado "vivo", que responde às consultas, está sempre na RAM; o disco serve só de rede de segurança.

E aqui está a sacada que amarra o artigo inteiro: a hierarquia do hardware se repete na arquitetura de software, com os mesmos papéis.

Hardware e Redis: o mesmo padrão de hierarquia

Isso tem duas consequências práticas. Como o Redis mora na RAM, seu conjunto de dados precisa caber na memória disponível: RAM é mais cara e limitada que disco, então você não guarda terabytes nele. E o papel dele numa aplicação é ficar na frente de um banco de dados mais lento, guardando cópias do que é mais acessado para responder num piscar de olhos. É a mesma lógica do cache da CPU, só que um andar acima.


Fechando

Vale olhar de novo o caminho que a gente percorreu. Um bit é uma carga elétrica presa num capacitor; um transistor é a chave que controla o acesso a ela. Junte bilhões dessas células numa matriz endereçável, e você tem a RAM: rápida, volátil, mantida viva por um refresh constante. A CPU encontra qualquer byte porque o endereço nunca foi um mistério: ele já vinha na instrução. E quando você sobe para o software, encontra o Redis fazendo, um nível acima, exatamente a mesma dança entre uma camada rápida e volátil na frente e um armazenamento permanente atrás.

Esse é o padrão que se repete em toda a computação: coloque o que é mais usado o mais perto e o mais rápido possível, e tenha algo permanente atrás para não perder nada. Entender isso no nível do capacitor é o que faz a ficha cair sobre por que seu sistema é rápido ou lento, e o que você pode fazer a respeito.


Referências

Os vídeos abaixo foram o conteúdo que usei como base, e ajudam a visualizar de forma visual como tudo isso funciona: