Em poucas palavras : coletores de lixo não usam recursão. Eles apenas controlam o rastreio acompanhando essencialmente dois conjuntos (que podem ser combinados). A ordem de rastreamento e processamento de células é irrelevante, o que oferece considerável liberdade de implementação para representar os conjuntos. Portanto, existem muitas soluções que são realmente muito baratas no uso de memória. Isso é essencial, pois o GC é chamado precisamente quando o heap fica sem memória. As coisas são um pouco diferentes com grandes memórias virtuais, pois novas páginas podem ser facilmente alocadas e o inimigo não é falta de espaço, mas falta de localidade dos dados
.
Suponho que você esteja pensando em rastrear coletores de lixo, e não na contagem de referências à qual sua pergunta não parece se aplicar.
A questão está focada no custo da memória de rastreamento para acompanhar um conjunto: o conjunto (para não rastreado) de células de memória acessíveis que ainda contêm ponteiros que ainda não foram rastreados. Isso é apenas metade do problema de memória
para coleta de lixo. O GC também deve acompanhar outro conjunto: o conjunto V (para visitado) de todas as células que foram consideradas acessíveis, de modo a recuperar todas as outras células no final do processo. Discutir um e não o outro faz sentido limitado, pois eles podem ter um custo semelhante, usar soluções semelhantes e até mesmo serem combinados.UV
A primeira coisa a observar é que todos os GC de rastreamento seguem o mesmo modelo abstrato, com base na exploração sistemática do gráfico direcionado de células na memória acessível a partir do programa, onde as células de memória são vértices e ponteiros são as arestas direcionadas. Utiliza para isso os seguintes conjuntos:
o conjunto (visitado) de células já consideradas acessíveis pelo mutador , ou seja, o programa ou algoritmo para o qual o GC é realizado. O conjunto V é particionado em dois subconjuntos separados:
V = U ∪ T ;VVV=U∪T
o conjunto (não rastreado) de células visitadas com ponteiros que ainda não foram seguidos;U
o conjunto (rastreado) das células visitadas que tiveram todos os seus ponteiros rastreados.T
H
VUUT
UV
UcVUcUT
UUV=TVH−VV
VUUT
Também pulo detalhes sobre o que é uma célula, se eles vêm em um tamanho ou em muitos, como encontramos indicadores neles, como podem ser compactados e uma série de outras questões técnicas que você pode encontrar em livros e pesquisas sobre coleta de lixo .
U
Onde as implementações conhecidas diferem está na maneira como esses conjuntos são realmente representados. Muitas técnicas foram realmente usadas:
mapa de bits: algum espaço de memória é preservado para um mapa que possui um bit para cada célula de memória, que pode ser encontrado usando o endereço da célula. O bit está ativado quando a célula correspondente está no conjunto definido pelo mapa. Se apenas mapas de bits forem usados, você precisará de apenas 2 bits por célula.
Como alternativa, você pode ter espaço para um bit de tag especial (ou 2) em cada célula para marcá-lo.
log2pp
você pode testar um predicado no conteúdo da célula e em seus ponteiros.
você pode realocar a célula em uma parte livre da memória destinada a todas as células pertencentes ao conjunto representado.
VTTU
você pode realmente combinar essas técnicas, mesmo para um único conjunto.
Como dito, todos os itens acima foram usados por alguns coletores de lixo implementados, por mais estranhos que alguns possam parecer. Tudo depende das várias restrições da implementação. E eles podem ser bastante baratos no uso da memória, possivelmente ajudados pelo processamento de políticas de pedidos que podem ser livremente escolhidas para esse fim, pois não importam para o resultado final.
O que pode parecer o mais estranho, transferir células para uma nova área, é realmente muito comum: é chamado de coleção de cópias. É usado principalmente com memória virtual.
Claramente, não há recursão, e a pilha do algoritmo do mutador não precisa ser usada.
Outro ponto importante é que muitos GC modernos são implementados para grandes memórias virtuais . Então, conseguir espaço para implementar e lista ou pilha extra não é um problema, pois novas páginas podem ser facilmente alocadas. No entanto, em grandes memórias virtuais, o inimigo não é falta de espaço, mas falta de localidade . Em seguida, a estrutura que representa os conjuntos e seu uso deve ser voltada para preservar a localidade da estrutura de dados e da execução do GC. O problema não é o espaço, mas o tempo. Implementações inadequadas têm mais probabilidade de mostrar uma desaceleração inaceitável do que o estouro de memória.
Não dei referências a muitos algoritmos específicos, resultantes de várias combinações dessas técnicas, pois isso parece longo o suficiente.