Digamos que seja um coletor de lixo simultâneo de marcação e varredura.
Quando esse GC lida com ponteiros constantes, apenas os percorre (a partir das raízes) e marca todos os blocos de dados encontrados. Em seguida, varre tudo sem marcação. Um código de cliente deve marcar os blocos de dados que ele usa como raízes.
Mas o que fazer com variáveis? Aqui está uma situação:
V
é uma variável, que armazena um ponteiro para o objetoA
.Thread 1
lêV
e suspende.Thread 2
modificaV
e faz apontar para o objetoB
.- O coletor de lixo executa sua fase de "marcação" e encontra os que
A
não são mais referenciados, depois o desaloca durante a fase de "varredura". Thread 1
desperta e tenta usarA
(já lidoV
na etapa 2) marcando-o como root. E falha , porqueA
não existe mais.
Então, como lidar com isso?
O Thread 2
pode marcar o objeto substituído A
com um sinalizador especial de não remover (um sinalizador semelhante é usado para objetos alocados recentemente). Mas quando esse sinalizador deve ser removido? Claro que Thread 1
poderia fazer isso. Mas Thread 2
não sabe nada Thread 1
e, portanto, não pode ter certeza de que isso será feito sempre. Isso pode levar a A
nunca será liberado. E se o GC remover esse sinalizador, nada impede que ele A
seja removido quando o GC for executado pela segunda vez ...
As descrições rápidas e rápidas de coletores de lixo que li e lembrei de mencionar que o objeto substituído deve estar "acinzentado". Mas sem detalhes específicos. Um link para uma descrição mais detalhada da solução seria muito apreciado.
fonte
Você precisa marcar variáveis locais em algum momento durante a fase de marcação. Todas as variáveis locais, incluindo aquelas que normalmente vivem na pilha. De alguma forma.
Além disso, acho que isso deve ser feito durante a fase síncrona (todos os mutadores parados) da verificação de objetos modificados. De fato, o mesmo problema pode surgir mesmo sem considerar variáveis / registros locais. Considere o objeto A apontando para nulo e o objeto B apontando para C. Agora, você digitaliza o objeto A, um encadeamento mutador vem, copia a referência para C de B para A, anula B. E agora você começa a digitalizar B. E C escorregou debaixo dos seus dedos.
Não conheço nenhuma maneira de lidar com isso que não envolva parar os mutadores. A técnica usual é no final da fase de marcação para parar todos os mutadores e marcar novamente todos os objetos que eles sofreram mutação durante a fase principal de marcação. E inclua pilhas e registros nisso.
Normalmente, os registros de marcação são contornados, fazendo-o de forma síncrona chamando o coletor no encadeamento algumas vezes. Dentro da função de coletor, apenas suas próprias variáveis locais (que não são raízes) podem estar nos registradores, todas as outras variáveis locais na cadeia de chamadas estão na pilha, para que você possa caminhar pela pilha.
Como alternativa, você pode enviar um sinal para o thread. O manipulador de sinal forçará novamente todas as variáveis na pilha, para que você possa acompanhá-las. A desvantagem desse método é que ele depende da plataforma.
fonte