Pelo meu entendimento, a coleta de lixo em Java limpa alguns objetos se nada mais estiver "apontando" para esse objeto.
Minha pergunta é: o que acontece se tivermos algo assim:
class Node {
public object value;
public Node next;
public Node(object o, Node n) { value = 0; next = n;}
}
//...some code
{
Node a = new Node("a", null),
b = new Node("b", a),
c = new Node("c", b);
a.next = c;
} //end of scope
//...other code
a
, b
E c
deve ser lixo coletado, mas todos eles estão sendo referenciado por outros objetos.
Como a coleta de lixo Java lida com isso? (ou é simplesmente um dreno de memória?)
java
garbage-collection
AlexeyMK
fonte
fonte
Respostas:
O GC de Java considera os objetos "lixo" se eles não puderem ser acessados através de uma cadeia iniciada em uma raiz de coleta de lixo, para que esses objetos sejam coletados. Mesmo que os objetos possam apontar um para o outro para formar um ciclo, eles ainda serão lixo se forem cortados da raiz.
Consulte a seção sobre objetos inacessíveis no Apêndice A: A verdade sobre a coleta de lixo no desempenho da plataforma Java: Estratégias e táticas para obter detalhes sangrentos.
fonte
O coletor de lixo Java lida com referência circular!
Existem objetos especiais chamados raízes de coleta de lixo (raízes da GC). Estes são sempre alcançáveis, assim como qualquer objeto que os tenha em sua própria raiz.
Um aplicativo Java simples possui as seguintes raízes de GC:
Para determinar quais objetos não estão mais em uso, a JVM executa intermitentemente o que é muito apropriadamente chamado de algoritmo de marcação e varredura . Funciona da seguinte maneira
Portanto, se algum objeto não estiver acessível a partir das raízes do GC (mesmo que seja auto-referenciado ou cíclico), ele será submetido à coleta de lixo.
É claro que às vezes isso pode levar ao vazamento de memória se o programador esquecer de desreferenciar um objeto.
Fonte: Gerenciamento de Memória Java
fonte
Um coletor de lixo inicia a partir de um conjunto "raiz" de locais que são sempre considerados "alcançáveis", como registros da CPU, pilha e variáveis globais. Ele funciona encontrando qualquer ponteiro nessas áreas e encontrando recursivamente tudo o que aponta. Uma vez encontrado tudo isso, tudo o resto é lixo.
É claro que existem algumas variações, principalmente por uma questão de velocidade. Por exemplo, a maioria dos coletores de lixo modernos é "geracional", o que significa que eles dividem objetos em gerações e, à medida que um objeto envelhece, o coletor de lixo fica cada vez mais longo entre as vezes em que tenta descobrir se esse objeto ainda é válido ou não. - apenas começa a supor que, se tiver vivido muito tempo, as chances são muito boas de que ele continue a viver ainda mais.
No entanto, a idéia básica permanece a mesma: tudo se baseia em partir de um conjunto raiz de coisas que é dado como certo ainda podem ser usadas e, em seguida, buscar todos os indicadores para descobrir o que mais poderia estar em uso.
Interessante à parte: muitas vezes as pessoas se surpreendem com o grau de semelhança entre essa parte de um coletor de lixo e o código para organizar objetos para coisas como chamadas de procedimentos remotos. Em cada caso, você está começando a partir de um conjunto raiz de objetos e perseguindo ponteiros para encontrar todos os outros objetos aos quais se refere ...
fonte
Você está certo. A forma específica de coleta de lixo que você descreve é chamada " contagem de referência ". A maneira como funciona (conceitualmente, pelo menos, as implementações mais modernas da contagem de referência são realmente implementadas de maneira bastante diferente) no caso mais simples, é assim:
E essa estratégia simples tem exatamente o problema que você descreve: se A fizer referência a B e B fazer referência a A, ambas as contagens de referência nunca poderão ser inferiores a 1, o que significa que nunca serão coletadas.
Existem quatro maneiras de lidar com esse problema:
A propósito, a outra maneira principal de implementar um coletor de lixo (e eu já sugeri isso algumas vezes acima) é traçar . Um coletor de rastreamento é baseado no conceito de alcançabilidade . Você começa com um conjunto raiz que você sabe que está sempre acessível (constantes globais, por exemplo, ou a
Object
classe, o escopo lexical atual, o quadro de pilha atual) e a partir daí você rastreia todos os objetos que são acessíveis a partir do conjunto raiz. todos os objetos acessíveis a partir dos objetos acessíveis a partir do conjunto raiz e assim por diante, até que você tenha o fechamento transitivo. Tudo o que não está nesse fechamento é lixo.Como um ciclo é acessível apenas dentro de si, mas não é acessível a partir do conjunto raiz, ele será coletado.
fonte
Os Java GCs na verdade não se comportam como você descreve. É mais preciso dizer que eles começam com um conjunto básico de objetos, freqüentemente chamados de "raízes do GC", e coletam qualquer objeto que não possa ser alcançado a partir de uma raiz.
As raízes do GC incluem coisas como:
Portanto, no seu caso, quando as variáveis locais a, bec estiverem fora do escopo no final do seu método, não haverá mais raízes do GC que contenham, direta ou indiretamente, uma referência para qualquer um dos seus três nós, e eles serão elegíveis para a coleta de lixo.
O link do TofuBeer tem mais detalhes, se você desejar.
fonte
Este artigo (não está mais disponível) detalha o coletor de lixo (conceitualmente ... existem várias implementações). A parte relevante para sua postagem é "A.3.4 Inacessível":
fonte
Coleta de lixo geralmente não significa "limpar algum objeto se nada mais estiver" apontando "para esse objeto" (isso é contagem de referência). A coleta de lixo significa aproximadamente encontrar objetos que não podem ser alcançados no programa.
Portanto, no seu exemplo, depois que a, bec estão fora do escopo, eles podem ser coletados pelo GC, pois você não pode mais acessar esses objetos.
fonte
Bill respondeu sua pergunta diretamente. Como Amnon disse, sua definição de coleta de lixo é apenas uma contagem de referência. Eu só queria acrescentar que mesmo algoritmos muito simples, como marcar e varrer e copiar coleção, lidam facilmente com referências circulares. Então, nada de mágico nisso!
fonte