Pular para conteúdo

JVM e Coleta de Lixo

O código Java é compilado em arquivos de classe que contêm bytecode e metadados. Uma JVM carrega, verifica, vincula, inicializa e executa classes. Interpretação e compilação just-in-time são estratégias de implementação que preservam contratos observáveis da linguagem e da JVM.

Áreas de dados em tempo de execução

  • cada thread possui uma pilha da JVM com quadros para as invocações de método ativas;
  • objetos e arrays são geralmente alocados em um heap compartilhado;
  • metadados de classe e estruturas do runtime são gerenciados separadamente pela JVM;
  • métodos nativos e buffers off-heap podem consumir memória fora do heap Java.

A especificação define áreas abstratas de dados em tempo de execução, não um layout universal de memória nem um custo em bytes.

Alcance e coleção

Coletores de lixo recuperam objetos que não são mais alcançáveis segundo o modelo de raízes do coletor. O momento da coleta não é determinístico, e a finalização não é um mecanismo de gerenciamento de recursos. Feche arquivos, sockets e outros recursos escassos explicitamente com try-with-resources.

Diferentes coletores otimizam objetivos como throughput, tempo de pausa, consumo de memória ou escalabilidade. Um coletor não impede vazamentos de memória: reter por uma referência viva um objeto desnecessário mantém esse objeto alcançável.

Inicialização de classe

Inicialização de classe tem garantias de sincronização e happens-before. É uma forma segura de publicar estado estático imutável, mas ciclos de inicialização e trabalho estático pesado podem dificultar o raciocínio sobre o comportamento.

Raciocínio de desempenho

A compilação JIT pode realizar inlining, especializar, eliminar alocações e remover trabalho morto quando o comportamento observável é preservado. Isso explica por que ler o código-fonte e contar alocações não substitui a análise de desempenho. Da mesma forma, um log de GC ou o tamanho do heap não basta para selecionar um coletor.

Use Java Flight Recorder, análise de heap, profiling de alocação, logs GC e JMH de acordo com a pergunta. Meça cargas representativas e diferencie as distribuições de latência do throughput. O guia de depuração e análise de desempenho conecta essas ferramentas à análise de CPU, memória e concorrência orientada por hipóteses.

Exercícios

  1. Explicar como uma coleção estática pode causar um memory leak lógico.
  2. Contrastar exaustão de heap com exaustão de memória nativa.
  3. Explicar por que System.gc() não é um contrato de ciclo de vida de recursos.