Memoria e Enderecos
Video da aula estara disponivel em breve
Enderecos Fisicos vs. Virtuais
Toda instrucao e dado que a CPU processa esta em algum endereco de memoria. Mas quando um programa referencia o endereco 0x4000, esse nao e necessariamente o endereco fisico na RAM. Existem dois espacos de enderecamento:
- Endereco fisico: o endereco real na RAM hardware. Vai de 0 ate o tamanho da memoria instalada.
- Endereco virtual (logico): o endereco que o programa "ve". Traduzido pelo hardware (MMU) para endereco fisico em tempo de execucao.
Diagrama — Traducao de Enderecos
Programa ve: RAM real:
+------------------+ +------------------+
| 0x0000: code | | 0x0000: [kernel] |
| 0x1000: data | MMU | 0x1000: [kernel] |
| 0x2000: heap | ------> | 0x2000: [Proc B] |
| ... | | 0x3000: [Proc A code] ← 0x0000 virtual
| 0xFFFF: stack | | 0x4000: [Proc A data] ← 0x1000 virtual
+------------------+ | 0x5000: [livre] |
| 0x6000: [Proc B] |
Espaco virtual do | 0x7000: [Proc A heap] ← 0x2000 virtual
Processo A +------------------+
A MMU (Memory Management Unit) traduz CADA acesso
a memoria. O programa nunca ve enderecos fisicos.
Por que enderecos virtuais?
Sem enderecos virtuais, cada programa precisaria saber exatamente onde na RAM esta carregado. Dois programas nao poderiam usar o mesmo endereco. Recompilar ou realocar programas seria necessario. Enderecos virtuais permitem que cada processo "pense" que tem toda a memoria para si, comecando do endereco 0.
Layout de Memoria de um Processo
Diagrama — Memory Layout
Enderecos altos (ex: 0x7FFF...)
+-----------------------------------+
| Stack | Variaveis locais, enderecos de
| | | retorno. Cresce para BAIXO.
| v | Tamanho tipico: 8MB (ulimit -s)
| |
| (espaco livre) |
| |
| ^ |
| | |
| Heap | malloc()/new. Cresce para CIMA.
| | Tamanho: ilimitado (ate swap).
+-----------------------------------+
| BSS | Globais nao-inicializadas.
| | Preenchidas com zero pelo SO.
+-----------------------------------+
| Data | Globais inicializadas.
| | int x = 42; fica aqui.
+-----------------------------------+
| Text (Code) | Instrucoes do programa.
| | Read-only. Compartilhavel.
+-----------------------------------+
Enderecos baixos (ex: 0x0040...)
C — Observando o layout de memoria
#include <stdio.h>
#include <stdlib.h>
int global_init = 42; // segmento Data
int global_uninit; // segmento BSS
int main() {
int local_var = 10; // Stack
int *heap_var = malloc(sizeof(int)); // Heap
printf("Enderecos (virtuais):\n");
printf(" Code (main): %p\n", (void*)main);
printf(" Data (init): %p\n", (void*)&global_init);
printf(" BSS (uninit): %p\n", (void*)&global_uninit);
printf(" Heap (malloc): %p\n", (void*)heap_var);
printf(" Stack (local): %p\n", (void*)&local_var);
free(heap_var);
return 0;
}
/* Saida tipica (enderecos simplificados):
Code (main): 0x401136
Data (init): 0x404030
BSS (uninit): 0x404034
Heap (malloc): 0x1234560
Stack (local): 0x7ffd8a3b4c
Note: Stack muito acima, Heap no meio, Code embaixo.
*/
Shell — Inspecionando memoria de um processo
# Ver o mapa de memoria de um processo
$ cat /proc/self/maps
00400000-00401000 r--p /usr/bin/cat # Text (read-only)
00401000-00404000 r-xp /usr/bin/cat # Text (executable)
00404000-00406000 r--p /usr/bin/cat # Data (read-only)
00406000-00407000 rw-p /usr/bin/cat # Data (read-write)
01234000-01255000 rw-p [heap] # Heap
7f8a00000-7f8b00000 r-xp /lib/libc.so # Shared library
7ffd80000-7ffda0000 rw-p [stack] # Stack
# Colunas: endereco, permissoes (r/w/x/p), path
# p = private (copy-on-write), s = shared
# Resumo de uso de memoria
$ pmap 1234 # mapa de memoria do PID 1234
$ free -h # uso de memoria do sistema
Protecao de Memoria
O SO garante que um processo nao pode acessar a memoria de outro. Cada processo tem sua propria tabela de paginas, e a MMU verifica cada acesso:
- Se o endereco virtual nao esta mapeado: segmentation fault
- Se a permissao e violada (escrever em read-only): segmentation fault
- Se acessa alem do limite da stack: stack overflow
Segmentation fault
O infame "segfault" e o SO protegendo voce (e outros processos) de um acesso invalido a memoria. Sem protecao de memoria (como no MS-DOS), um programa bugado poderia corromper a memoria de qualquer outro programa ou do proprio SO.
No harness.os
A context window de um LLM e analoga ao espaco de enderecamento de um processo:
Diagrama — Context Window como Memoria
Memoria de Processo (SO) Context Window (LLM)
======================== =========================
+------------------+ +---------------------------+
| Stack | | Conversa recente |
| (variaveis | | (ultimas mensagens, |
| locais) | | estado ativo) |
+------------------+ +---------------------------+
| (espaco livre) | | (espaco disponivel) |
+------------------+ +---------------------------+
| Heap | | Knowledge carregado |
| (alocacao | | (get_knowledge(), rules, |
| dinamica) | | workflows sob demanda) |
+------------------+ +---------------------------+
| Data/BSS | | System prompt / CLAUDE.md |
| (globais) | | (sempre presente, |
| | | "inicializado" no start) |
+------------------+ +---------------------------+
| Text | | Model weights |
| (instrucoes) | | (fixo, read-only, |
| | | compartilhado) |
+------------------+ +---------------------------+
Stack overflow = context window cheia (compaction)
malloc() = get_knowledge() (alocar espaco para dados)
free() = conhecimento sai do contexto
Segfault = hallucination (acessar "memoria" que nao existe)
Python — Context window como espaco de enderecamento
class ContextMemory:
"""Context window modelada como espaco de enderecamento."""
def __init__(self, max_tokens=200000):
self.max_tokens = max_tokens
self.text = "model weights" # fixo, nao conta
self.data = [] # system prompt, CLAUDE.md
self.heap = [] # knowledge carregado
self.stack = [] # conversa ativa
def malloc(self, knowledge_chunk):
"""Carregar conhecimento = alocar no heap."""
tokens = count_tokens(knowledge_chunk)
if self.used() + tokens > self.max_tokens:
raise MemoryError("Context window cheia")
self.heap.append(knowledge_chunk)
def used(self):
return sum(count_tokens(x) for x in self.data + self.heap + self.stack)
Homework
- Compile e execute o programa de enderecos. Compare os enderecos com o
/proc/PID/mapsdo processo. - Escreva um programa que causa um segmentation fault de 3 formas diferentes: (a) dereferencia NULL, (b) escreve em memoria read-only, (c) acessa alem de um array.
- No harness.os, calcule o "uso de memoria" de uma sessao tipica: system prompt (~X tokens) + handoff (~Y tokens) + knowledge (~Z tokens) + conversa (~W tokens). Qual percentual da context window (200k tokens) esta "livre"?
Resumo
- Enderecos virtuais sao traduzidos para fisicos pela MMU em tempo de execucao
- Layout: text (code) → data → BSS → heap (cresce para cima) → stack (cresce para baixo)
/proc/PID/mapsmostra o mapa de memoria virtual de qualquer processo- Protecao de memoria: cada processo isolado, acessos invalidos geram segfault
Verifique seu entendimento
Se dois processos diferentes acessam o endereco virtual 0x4000, eles estao acessando o mesmo byte na RAM fisica?