Memória Virtual
Vídeo da aula estará disponível em breve
Por que Memória Virtual?
Sem memória virtual, cada programa precisaria saber exatamente quais endereços físicos de RAM estão disponíveis, e dois programas não poderiam usar o mesmo endereço. A memória virtual resolve três problemas fundamentais:
1. ILUSÃO DE MEMÓRIA ILIMITADA
Cada processo acha que tem 4 GB (32-bit) ou 256 TB (64-bit)
de memória contígua, mesmo que a RAM física tenha apenas 8 GB.
Páginas não usadas ficam em disco (swap).
2. ISOLAMENTO ENTRE PROCESSOS
Processo A não pode acessar memória de Processo B.
Endereço virtual 0x1000 de A mapeia para um endereço físico
diferente de 0x1000 de B. Cada processo tem seu próprio
espaço de endereçamento.
3. PROTEÇÃO DE MEMÓRIA
Bits de proteção na page table controlam:
- Read (R): pode ler?
- Write (W): pode escrever?
- Execute (X): pode executar como código?
Código do kernel: apenas kernel pode acessar.
Código do programa: R+X (read + execute, não write).
Dados: R+W (read + write, não execute).
Paginação: Endereços Virtuais e Físicos
A memória é dividida em blocos de tamanho fixo chamados páginas (no espaço virtual) e frames (no espaço físico). A page table mantém o mapeamento entre eles.
Endereço Virtual (32 bits, páginas de 4 KB = 2^12 bytes):
┌─────────────────────┬──────────────┐
│ Virtual Page Number │ Page Offset │
│ (20 bits) │ (12 bits) │
└─────────────────────┴──────────────┘
│ │
▼ │ (offset não muda)
┌──────────┐ │
│ Page │ │
│ Table │ │
│ │ │
│ VPN → PFN│ │
└────┬─────┘ │
│ │
▼ ▼
┌─────────────────────┬──────────────┐
│ Physical Frame Number│ Page Offset │
│ (18 bits*) │ (12 bits) │
└─────────────────────┴──────────────┘
Endereço Físico (30 bits para 1 GB de RAM*)
*Exemplo: 1 GB RAM = 2^30 bytes, frame de 4 KB = 2^12
Total de frames = 2^30 / 2^12 = 2^18 = 262.144 frames
Exemplo concreto:
Endereço virtual: 0x00003A7C
VPN = 0x00003 = página virtual 3
Offset = 0xA7C = byte 2684 dentro da página
Page table diz: VPN 3 → PFN 0x2F1 (frame 753)
Endereço físico: 0x2F1A7C
= frame 753, byte 2684 dentro do frame
A Page Table
A page table é uma estrutura em memória (DRAM) que o hardware consulta para traduzir cada endereço virtual em físico. Cada entrada (PTE — Page Table Entry) contém:
┌───────┬───┬───┬───┬───┬───┬─────────────────────────┐
│ Valid │ R │ W │ X │ D │ A │ Physical Frame Number │
│ (1b) │(1)│(1)│(1)│(1)│(1)│ (18+ bits) │
└───────┴───┴───┴───┴───┴───┴─────────────────────────┘
Valid (V): 1 = página está na RAM; 0 = não está (page fault)
Read (R): permissão de leitura
Write (W): permissão de escrita
Execute (X): permissão de execução
Dirty (D): 1 = página foi modificada (precisa write-back para disco)
Accessed (A): 1 = página foi acessada recentemente (usado pelo SO para LRU)
PFN: número do frame físico onde a página está
Tamanho da page table:
32-bit, páginas de 4 KB: 2^20 = 1.048.576 entradas
Cada PTE = 4 bytes → page table = 4 MB POR PROCESSO
Se 100 processos: 400 MB só de page tables!
64-bit, páginas de 4 KB: 2^52 entradas = impossível!
→ Solução: page tables multinível
TLB: Translation Lookaside Buffer
Cada acesso à memória requer consultar a page table, que está na DRAM. Isso duplicaria o tempo de acesso (1 acesso para a page table + 1 para o dado). O TLB é uma cache especializada para traduções de endereço:
CPU gera endereço virtual
│
▼
┌──────────┐
│ TLB │ Cache de traduções (32-128 entradas, fully associative)
│ VPN → PFN│ Hit time: 0.5-1 ciclo
└────┬─────┘
│
Hit? ─┬─ SIM → Endereço físico pronto (rápido!)
│
└─ NÃO (TLB miss) → Consulta page table na DRAM
│
Page em RAM? ─┬─ SIM → Atualiza TLB, retenta
│
└─ NÃO → PAGE FAULT (exceção)
│
▼
SO carrega página
do disco para RAM
(milhões de ciclos!)
Desempenho típico:
TLB hit rate: 99%+ (poucas entradas bastam pela localidade)
TLB miss + page table hit: ~10-100 ciclos
Page fault: ~1-10 ms (acesso a disco) = milhões de ciclos
TLB é ESSENCIAL: sem ela, todo acesso à memória seria 2×
mais lento (acessar page table + acessar dado).
Flush do TLB:
Quando o SO troca de processo (context switch), o TLB precisa
ser invalidado (entradas do processo anterior são inválidas).
Alternativa: ASID (Address Space ID) — cada entrada tem um tag
de processo, evitando flush completo.
Page Fault e Tratamento
Um page fault ocorre quando o processador tenta acessar uma página virtual que não está na RAM (bit Valid = 0 na PTE). O hardware gera uma exceção e o SO assume o controle:
1. CPU acessa endereço virtual → TLB miss → Page table: Valid = 0
2. Hardware gera EXCEÇÃO (page fault trap)
3. SO assume controle (modo kernel)
4. SO localiza a página no disco (swap ou arquivo mapeado)
5. SO escolhe um frame na RAM para substituir:
- Se frame sujo (dirty = 1): escreve de volta no disco
- Se frame limpo: substitui direto
6. SO inicia leitura do disco para o frame escolhido
(operação de I/O, leva milhões de ciclos)
Enquanto espera: SO escalona outro processo
7. Quando I/O completa (interrupção):
- SO atualiza page table (Valid = 1, PFN = novo frame)
- SO atualiza TLB
- SO reinicia a instrução que causou o fault
Latência:
Acesso à RAM: ~100 ns
Page fault (SSD): ~50-100 μs (500-1000× mais lento)
Page fault (HDD): ~5-10 ms (50.000-100.000× mais lento)
Por isso memória virtual usa write-back (não write-through)
e fully associative (qualquer frame para qualquer página):
a penalidade de miss é TÃO alta que vale qualquer custo
de hardware para minimizar misses.
Page Tables Multinível
Em sistemas 64-bit, uma page table plana teria 252 entradas — impossível armazená-la. A solução é usar múltiplos níveis de page table, onde cada nível aponta para o próximo:
Endereço Virtual (32 bits):
┌──────────┬──────────┬──────────────┐
│ P1 (10b) │ P2 (10b) │ Offset (12b) │
└──────────┴──────────┴──────────────┘
Page Directory (nível 1): 1024 entradas
Cada entrada aponta para uma Page Table (nível 2)
Apenas entradas usadas apontam para tables; as outras = NULL
Page Table (nível 2): 1024 entradas cada
Cada entrada contém o PFN
┌────────────────┐
P1 ───────► │ Page Directory │
│ (1024 entradas)│
└───────┬────────┘
│ entrada P1
▼
┌────────────────┐
P2 ───────► │ Page Table │
│ (1024 entradas)│
└───────┬────────┘
│ entrada P2
▼
PFN + Offset = Endereço Físico
Vantagem: se um processo usa apenas 1% do espaço de endereçamento,
apenas 1% das page tables de nível 2 existem. Economia enorme.
x86-64 usa 4 níveis (PML4):
Endereço virtual (48 bits usados):
[PML4: 9b][PDPT: 9b][PD: 9b][PT: 9b][Offset: 12b]
4 acessos à memória para traduzir 1 endereço (sem TLB!)
→ TLB é AINDA mais crítico em sistemas 64-bit.
x86-64 com 5-Level Paging (LAM): 57 bits de endereço virtual
Permite endereçar até 128 PB de espaço virtual.
Hierarquia Completa: TLB, Cache e Memória Virtual
CPU gera endereço VIRTUAL
│
┌────┴────┐
│ TLB │ hit (99%) → endereço FÍSICO
└────┬────┘
miss (1%) │
│
┌────┴─────────┐
│ Page Table │ → endereço FÍSICO (+ atualiza TLB)
│ (na DRAM) │
└────┬─────────┘
page fault (0.001%) │
│ │
┌────┴────┐ │
│ Disco │ │
│ (swap) │ │
└────┬────┘ │
│ │
▼ ▼
Endereço FÍSICO disponível
│
┌────┴────┐
│ Cache L1│ hit (95%) → DADO (1-2 ciclos)
└────┬────┘
miss (5%) │
│
┌────┴────┐
│ Cache L2│ hit (80%) → DADO (5-10 ciclos)
└────┬────┘
miss (20%) │
│
┌────┴────┐
│ Cache L3│ hit (90%) → DADO (20-30 ciclos)
└────┬────┘
miss (10%) │
│
┌────┴────┐
│ DRAM │ → DADO (100 ciclos)
└─────────┘
Observação importante:
TLB e Cache L1 operam EM PARALELO em muitos processadores.
A cache L1 pode ser "Virtually Indexed, Physically Tagged" (VIPT):
usa bits do endereço virtual para indexar (em paralelo com TLB)
e bits do endereço físico para comparar tags (após TLB).
No harness.os
Memória virtual dá a cada processo a ilusão de ter toda a memória para si — isolamento. O harness.os dá a cada agente um contexto isolado (sessão própria, variáveis locais), mesmo compartilhando a infraestrutura.
Memória Virtual harness.os
───────────────────────────── ──────────────────────────────────────
Endereço virtual Session context (visão local do agente)
Cada processo vê seu espaço Cada sessão vê seus rules, knowledge,
próprio de endereçamento handoff — isolado de outras sessões
Page table (VPN → PFN) Session registry (session → project)
Mapeia virtual para físico Mapeia sessão para projeto e dados
TLB (cache de traduções) start_session cache
Tradução rápida sem ir à DRAM Retorna handoff+rules sem queries
adicionais ao banco
Page fault Knowledge miss
Página não está na RAM Informação não está no contexto
→ SO busca do disco → Agente busca via search_knowledge()
→ Muito lento → Tool call ao Neon Postgres
Proteção (R/W/X bits) Governance concern
Controla quem pode fazer o quê Rules controlam quais tools um
em cada página de memória agente pode usar em qual contexto
Context switch Session handoff
SO salva estado do processo A end_session salva contexto
e carrega estado do processo B start_session carrega do próximo
Thrashing Context overflow
Muitas páginas ativas, pouca Muito conhecimento necessário,
RAM → sistema trava pouca context window → compaction
Homework
- Um sistema tem endereços virtuais de 32 bits, páginas de 8 KB e memória física de 512 MB. Calcule: (a) número de páginas virtuais, (b) número de frames físicos, (c) bits para VPN, PFN e offset.
- Dado o mapeamento abaixo, traduza o endereço virtual 0x00005A30 para endereço físico:
O que acontece se tentar acessar 0x00007100?Page Table (parcial)
VPN Valid PFN ─── ───── ─── 0x003 1 0x1F 0x005 1 0x0A 0x007 0 --- 0x00A 1 0x33 - Explique por que memória virtual usa "fully associative" (qualquer página pode ir para qualquer frame) enquanto cache L1 geralmente é 4-way ou 8-way. Dica: pense na penalidade de miss de cada uma.
- No harness.os, o context switch entre processos invalida o TLB. Quando você faz end_session seguido de start_session em outro projeto, o que é "invalidado" no contexto do agente? Como isso se compara ao flush do TLB?
Resumo
- Memória virtual provê ilusão de memória ilimitada, isolamento entre processos e proteção via bits R/W/X
- Paginação divide memória em páginas (virtual) e frames (físico); page table faz o mapeamento
- TLB: cache de traduções com hit rate >99%; essencial para não duplicar tempo de acesso
- Page fault: página não está na RAM; SO carrega do disco (milhões de ciclos de penalidade)
- Page tables multinível: evitam tabelas enormes em sistemas 64-bit (x86-64 usa 4 níveis)
- Hierarquia completa: TLB → Page Table → Cache L1 → L2 → L3 → DRAM → Disco
Verifique seu entendimento
O que acontece quando o processador acessa um endereço virtual cuja entrada na page table tem Valid = 0?