College Online
0%

Memória Virtual

Módulo 5 · Aula 2 ~22 min de leitura Nível: Intermediário

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:

Os Três Problemas que Memória Virtual Resolve
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.

Diagrama — Tradução de Endereço
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:

Estrutura de uma Page Table Entry (PTE)
┌───────┬───┬───┬───┬───┬───┬─────────────────────────┐
│ 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:

Diagrama — TLB
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:

Diagrama — Tratamento de Page Fault
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.
i
Thrashing Se um sistema tem mais páginas ativas que frames de RAM, ocorre thrashing: o SO gasta mais tempo movendo páginas entre RAM e disco do que executando o programa. O sistema fica praticamente parado. Solução: mais RAM, ou reduzir o working set dos processos.

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:

Diagrama — Page Table de 2 Níveis (32-bit)
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

Diagrama — Fluxo Completo de Acesso à Memória
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.

Mapeamento: Memória Virtual → harness.os
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

  1. 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.
  2. Dado o mapeamento abaixo, traduza o endereço virtual 0x00005A30 para endereço físico:
    Page Table (parcial)
    VPN    Valid  PFN
    ───    ─────  ───
    0x003    1    0x1F
    0x005    1    0x0A
    0x007    0    ---
    0x00A    1    0x33
    O que acontece se tentar acessar 0x00007100?
  3. 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.
  4. 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

Verifique seu entendimento

O que acontece quando o processador acessa um endereço virtual cuja entrada na page table tem Valid = 0?

  • O processador retorna zero como valor padrão
  • O TLB cria automaticamente uma nova tradução
  • O processador acessa a memória física diretamente sem tradução
  • Ocorre um page fault: o hardware gera uma exceção e o SO carrega a página do disco para a RAM