oi!! (。♥‿♥。) memória é disputada. todo processo quer um pedaço, e o SO precisa dividir esse bolo sem deixar ninguém brigando. nesse tema a gente vê como o SO organiza a memória, desde o básico até a mágica da memória virtual. bora!! ٩(◕‿◕)۶
1. Alocação Contígua: O Começo Simples
a forma mais óbvia de dividir memória é alocar cada processo num bloco contínuo de endereços. tipo dividir uma pizza em fatias inteiras: cada um pega sua fatia e não mexe na do outro. (。◕‿◕。)
existem duas abordagens:
- Partições fixas: a memória é dividida em pedaços de tamanho igual. simples, mas se o processo é menor que a partição, o resto vira fragmentação interna (espaço desperdiçado dentro da partição).
- Partições variáveis: cada processo pega exatamente o que precisa. melhor uso da memória, mas cria fragmentação externa (sobram buracos espalhados que, somados, dariam espaço, mas isoladamente não servem).
imagina que vc tem buracos de 10KB, 20KB e 15KB espalhados. total = 45KB. mas seu processo precisa de 30KB contínuos. não cabe em lugar nenhum, mesmo havendo espaço no total. é como tentar estacionar um carro numa rua cheia de motos: sobra espaço, mas não organizado. (╥﹏╥)
pra alocar em partições variáveis, existem estratégias:
- First-fit: primeiro buraco que couber. rápido, mas pode deixar buracos pequenos no começo.
- Best-fit: o menor buraco que couber. teoricamente melhor, mas deixa mini-burcos inúteis. fragmentação externa piora.
- Worst-fit: o maior buraco. ideia: sobra espaço grande ainda útil. na prática, não é melhor que os outros.
2. Paginação: Dividindo em Páginas
a paginação resolve o problema da fragmentação externa. a ideia é simples: divide a memória física em blocos fixos chamados quadros (frames) e a memória lógica do processo em blocos do mesmo tamanho chamados páginas. cada página vai parar num quadro livre, não importa onde. (•̀ᴗ•́)و
como as páginas não precisam ser contíguas, acabou a fragmentação externa. pode sobrar um pouco no final da última página (fragmentação interna), mas é no máximo o tamanho de uma página, o que é aceitável.
o SO usa uma tabela de páginas pra saber onde cada página do processo foi parar na memória física. o endereço lógico é dividido em número da página e deslocamento (offset). a tabela traduz número da página → número do quadro. o deslocamento é o mesmo, porque página e quadro têm o mesmo tamanho.
o processo vê um mundo de endereços sequenciais (lógicos). mas na memória RAM, suas páginas estão espalhadas. a tabela de páginas é o mapa que traduz esse mundo imaginário pro mundo real. é tipo GPS: vc vê a rota limpa, mas por baixo tem um monte de conversão de coordenadas. (⌐■_■)
3. TLB: Cache da Tabela de Páginas
a tabela de páginas fica na memória principal. toda vez que o processador acessa um endereço, precisa consultar essa tabela. isso dobrou o tempo de acesso: uma pra tabela, outra pro dado. lento!! (T_T)
a solução é a TLB (Translation Lookaside Buffer): uma cache pequena e rápida que guarda as traduções de página mais usadas. se o número da página tá na TLB (TLB hit), a tradução é instantânea. se não tá (TLB miss), vai na tabela de páginas na RAM e atualiza a TLB. (☆▽☆)
por causa do princípio da localidade (lembra da Unidade 3?), a TLB tem taxa de acerto alta, tipo 90% ou mais. sem ela, a paginação seria muito lenta. é um componente essencial dos processadores modernos.
processadores modernos têm TLB para páginas de diferentes tamanhos (4KB, 2MB, 1GB). páginas grandes (huge pages) são usadas em bancos de dados e aplicações que consomem muita memória, porque reduzem miss na TLB. é um tuning avançado, mas que faz diferença em servidores. (。•̀ᴗ-)✧
4. Segmentação: Dividindo por Lógica
a segmentação divide a memória do processo em blocos de tamanhos variáveis segundo a lógica do programa: código, dados, pilha, heap, bibliotecas. cada segmento é uma unidade independente. (✿◠‿◠)
o endereço lógico tem dois campos: número do segmento e deslocamento. a tabela de segmentos guarda o endereço base e o limite de cada segmento. se o deslocamento passar do limite, dá segmentation fault (falha de segmentação). famosa tela de erro!! (T_T)
vantagem: reflete a organização lógica do programa. proteção é mais natural (pode marcar segmento de código como somente leitura). desvantagem: sofre de fragmentação externa, porque segmentos têm tamanhos diferentes. por isso, sistemas modernos combinam segmentação com paginação: segmentação paginada.
5. Memória Virtual: O Disco Virou RAM
agora vem a mágica. a memória virtual permite que um processo use mais memória do que existe fisicamente. como? usando o disco como extensão da RAM. páginas que não cabem na RAM vão pro disco (área de swap ou paging file). quando o processo precisa delas, o SO traz de volta. (ノ◕ヮ◕)ノ*:・゚✧
isso dá vários benefícios:
- Ilusão de memória infinita: processos podem ser maiores que a RAM.
- Isolamento: cada processo tem seu espaço de endereçamento virtual. não sabe que outros processos existem.
- Compartilhamento: páginas de código de bibliotecas podem ser mapeadas em vários processos (memória compartilhada).
- Facilidade de carregamento: só carrega páginas necessárias (paginação por demanda).
em vez de carregar o processo inteiro na RAM, o SO carrega só as páginas que o processo realmente usa. quando o processo tenta acessar uma página que não tá na RAM, acontece uma falta de página (page fault). o SO pega a página do disco, coloca num quadro livre, e continua a execução. é transparente pro programa. (◍•ᴗ•◍)
6. Algoritmos de Substituição de Página
quando a RAM tá cheia e ocorre um page fault, o SO precisa escolher uma página pra tirar da RAM e liberar espaço. qual escolher? aí entram os algoritmos de substituição. ( ͡~ ͜ʖ ͡°)
6.1 FIFO (First-In, First-Out)
tira a página que tá há mais tempo na RAM. simples, mas pode tirar uma página super usada só porque ela chegou cedo. tem o problema de anomalia de Belady: às vezes, aumentar o número de quadros piora a taxa de faltas. contraintuitivo e irritante. (¬‿¬)
6.2 Ótimo (OPT)
tira a página que não será usada pelo maior tempo futuro. é o melhor possível, mas impossível de implementar: exige saber o futuro. serve só como benchmark teórico. tipo aquele amigo que dá conselho perfeito, mas só depois que vc já se ferrou. ( ̄ω ̄)
6.3 LRU (Least Recently Used)
tira a página que não é usada há mais tempo. baseia-se no princípio da localidade temporal: se não usou recentemente, provavelmente não usará tão cedo. é próximo do ótimo e bastante usado na prática. mas exige hardware pra registrar o tempo de acesso, o que aumenta custo. (•̀ᴗ•́)و
6.4 Aproximação de LRU (Relógio / Second Chance)
pra simplificar o LRU, usa um bit de referência. toda página tem esse bit. quando a página é acessada, o bit vai pra 1. o algoritmo do relógio percorre as páginas em círculo. se o bit é 1, zera e dá "segunda chance". se é 0, substitui. é LRU barato e eficiente. usado no Linux. (。•̀ᴗ-)✧
FIFO: simples, mas burro. pode dar anomalia de Belady.
Ótimo: perfeito, mas impossível. referência teórica.
LRU: muito bom, mas custoso de implementar.
Relógio: aproximação barata do LRU. a escolha prática. (✧≖‿≖)
7. Thrashing: Quando a Memória Virtual Vira Pesadelo
Thrashing é quando o processo passa mais tempo trocando páginas entre RAM e disco do que executando. a taxa de page fault explode, o disco fica a 100%, e o sistema fica lento pra caramba. vc já viu isso quando abre 500 abas no Chrome com 4GB de RAM. (´;Д;`)
causa: muitos processos disputando pouca RAM. cada um precisa de mais páginas do que cabem, então ficam se empurrando. solução: diminuir o grau de multiprogramação (tirar processos da memória) ou aumentar a RAM. no Linux, o swappiness controla o quão agressivo é o uso de swap. ajustar isso pode ajudar. (ノ◕ヮ◕)ノ*:・゚✧
se seu PC tá lento e o LED do disco fica aceso o tempo todo, provavelmente é thrashing. o sistema tá desesperado trocando páginas. solução imediata: fecha programas. solução definitiva: compra mais RAM. ou usa Linux. ou os dois. (✿◠‿◠)
8. Considerações Finais
o gerenciamento de memória evoluiu de partições simples pra paginação, segmentação e memória virtual. hoje, praticamente todos os SOs usam paginação com memória virtual. a combinação de tabela de páginas, TLB, paginação por demanda e algoritmos de substituição permite rodar dezenas de apps simultaneamente com eficiência. (¬‿¬)
entender isso explica:
- por que mais RAM deixa o PC mais rápido (menos page faults).
- por que SSD melhora performance (swap mais rápido).
- por que o Chrome come memória (cada aba é processo com seu espaço virtual).
- por que "reiniciar" resolve problema de memória (limpa tudo).
no Linux, vmstat, free -h e /proc/meminfo mostram uso de memória e swap. no Windows, o Gerenciador de Tarefas tem a aba "Desempenho". quando vc entende o que tá vendo, deixa de ser números aleatórios e vira informação útil. (ノ◕ヮ◕)ノ*:・゚✧
fechou, senpai? (☆▽☆) até o próximo tema!! ヾ(^-^)ノ