Máquina Virtual Java - Coleta de Lixo
O ciclo de vida de um objeto Java é gerenciado pela JVM. Depois que um objeto é criado pelo programador, não precisamos nos preocupar com o resto do seu ciclo de vida. A JVM encontrará automaticamente os objetos que não estão mais em uso e recuperará sua memória do heap.
A coleta de lixo é uma operação importante que a JVM faz e ajustá-la para nossas necessidades pode dar um grande aumento de desempenho para nosso aplicativo. Há uma variedade de algoritmos de coleta de lixo fornecidos por JVMs modernos. Precisamos estar cientes das necessidades de nosso aplicativo para decidir qual algoritmo usar.
Você não pode desalocar um objeto programaticamente em Java, como pode fazer em linguagens não-GC, como C e C ++. Portanto, você não pode ter referências pendentes em Java. No entanto, você pode ter referências nulas (referências que se referem a uma área da memória onde a JVM nunca armazenará objetos). Sempre que uma referência nula é usada, a JVM lança uma NullPointerException.
Observe que, embora seja raro encontrar vazamentos de memória em programas Java graças ao GC, eles acontecem. Criaremos um vazamento de memória no final deste capítulo.
Os seguintes GCs são usados em JVMs modernos
- Coletor serial
- Coletor de rendimento
- Coletor CMS
- Coletor G1
Cada um dos algoritmos acima realiza a mesma tarefa - localizar objetos que não estão mais em uso e recuperar a memória que ocupam no heap. Uma das abordagens ingênuas para isso seria contar o número de referências que cada objeto tem e liberá-lo assim que o número de referências vire 0 (isso também é conhecido como contagem de referência). Por que isso é ingênuo? Considere uma lista ligada circular. Cada um de seus nós terá uma referência a ele, mas o objeto inteiro não está sendo referenciado de qualquer lugar e deve ser liberado, idealmente.
A JVM não apenas libera a memória, mas também une pequenos blocos de memória em outros maiores. Isso é feito para evitar a fragmentação da memória.
Em uma nota simples, um algoritmo de GC típico faz as seguintes atividades -
- Encontrar objetos não utilizados
- Libertando a memória que ocupam no heap
- Coalescendo os fragmentos
O GC deve interromper os threads do aplicativo enquanto está em execução. Isso ocorre porque ele move os objetos ao redor quando é executado e, portanto, esses objetos não podem ser usados. Essas paradas são chamadas de 'pausas stop-the-world e minimizar a frequência e a duração dessas pausas é o que buscamos ao sintonizar nosso GC.
Coalescência de memória
Uma demonstração simples de coalescência de memória é mostrada abaixo
A parte sombreada são objetos que precisam ser liberados. Mesmo depois de todo o espaço ser recuperado, só podemos alocar um objeto de tamanho máximo = 75Kb. Isso ocorre mesmo depois de termos 200Kb de espaço livre, conforme mostrado abaixo