[Notas de estudo da Lua] Lua Avançada - Coleta de Lixo

Insira a descrição da imagem aqui
De acordo com o curso do professor Tang, era para ensinar sobre bibliotecas integradas, mas pense bem, você pode ler documentos, ctrl + clique esquerdo também pode ler anotações, e o mais importante é que muitos dos métodos de construção - nas bibliotecas estão disponíveis na maioria dos idiomas. Na verdade, dê uma olhada Você entenderá. Então, vamos nos concentrar na coleta de lixo.

A maior parte do conteúdo a seguir foi extraído de [Lua] Explicação detalhada da coleta de lixo , análise do código-fonte Lua - mecanismo de implementação gc [versão detalhada] (1) , leia o artigo no link


CG

Se você tiver contato com Lua do Unity, saiba que também existe um mecanismo de GC em C#. Máquinas virtuais são usadas na maioria das linguagens orientadas a objetos, e a máquina virtual Mono também é usada no Unity. Nosso código está na memória virtual da máquina virtual. Na máquina virtual, o código deve ser convertido em um conjunto de instruções, compilado em bytecode e, finalmente, o conjunto de instruções traduzido em bytecode é usado em cada plataforma para obter implementação multiplataforma.

Como o espaço de memória ocupado pelo objeto é armazenado na memória virtual, isso não afetará a memória física. Quando a memória física precisar chamar o objeto, o bloco de memória virtual será atribuído à memória física. Se um bloco de memória virtual não for referenciado pela memória física por um longo período, a memória que ele ocupa deverá ser liberada.Isso é GC (garage collect).

De acordo
com a descrição oficial, Lua pode gerenciar automaticamente a memória através do mecanismo GC e eliminar objetos mortos.Os tipos desses objetos incluem: string, tabelas, dados do usuário, funções, threads, estruturas internas, etc.

Objetos considerados mortos não serão mais acessados ​​no programa (mas os finalizadores podem ressuscitar esses objetos mortos). O que o GC pensa que está morto é diferente do que o programador pensa. O GC pensa que está morto se ficar inativo por muito tempo. Se um objeto for considerado morto, ele não poderá mais ser acessado normalmente.

Usando funções collectgarbageou definindo metamétodos __gc, podemos usar ou substituir diretamente o mecanismo gc.


Coleta auxiliar de lixo

Embora a coleta automática de lixo seja aplicável na maioria das vezes, em alguns casos especiais ainda precisamos determinar nós mesmos os objetos e o momento da coleta de lixo. Para tanto, a linguagem Lua fornece uma forma de auxiliar na coleta de lixo.

  • Função collectgarbage: permite controlar o tamanho do passo do coletor de lixo
  • Destruidor (verifique recentemente a entrada GC do C#, o nome oficial da Microsoft em chinês é chamado finalizador ) (finalizador): permite a coleta de objetos externos que não estão sob o controle direto do coletor de lixo.
  • Tabela de referência fraca (tabela fraca): permite a coleção de objetos em Lua que também podem ser acessados ​​por programas (especialmente valores de chave nula na tabela)

coletar lixo

---@alias gcoptions
---|>"collect"      # 做一次完整的垃圾收集循环。
---| "stop"         # 停止垃圾收集器的运行。
---| "restart"      # 重启垃圾收集器的自动运行。
---| "count"        # 以 K 字节数为单位返回 Lua 使用的总内存数。
---| "step"         # 单步运行垃圾收集器。 步长“大小”由 `arg` 控制。
---| "isrunning"    # 返回表示收集器是否在工作的布尔值。
---| "incremental"  # 改变收集器模式为增量模式。
---| "generational" # 改变收集器模式为分代模式。

---
---这个函数是垃圾收集器的通用接口。 通过参数 opt 它提供了一组不同的功能。
---
function collectgarbage(opt, ...) end

// 使用方法collectgarbage("加内关键字")
collectgarbage("collect")  --主动进行一次垃圾回收(垃圾回收会回收nil的垃圾)

Cada vez que a coleta de lixo ocupa muita memória, use-a o mínimo possível e não a use automaticamente se puder fazê-lo manualmente.

collectgarbageSão fornecidos dois modos de reciclagem, nomeadamente modo incremental e modo geracional.

modo incremental

No modo incremental, cada ciclo gc usa o método mark-and-sweep para marcar e coletar gradualmente o lixo. O GC e o interpretador são executados juntos alternadamente (Lua5.1 e posterior, não há necessidade de interromper a execução do programa principal) Sempre que o intérprete aloca uma certa quantidade de memória, o coletor de lixo também executa uma etapa. Cada ciclo de GC consiste em quatro fases, nomeadamente marcação, limpeza, varredura e finalização:

collectgarbage("incremental",200,200,13)
1)、garbage-collector pause, 
    什么时间执行,比上次回收后内增加的比例 默认200% 最大1000%
2)、garbage-collector step multiplier, 
相对说内存分配而言的一个比例,也就是是以什么速度收集 默认 200% 最大 1000%
3)、 the garbage-collector step size
控制每次回收的步幅?解释器分配的字节数 默认是 213次 约 8K

A maior parte do conteúdo a seguir foi extraído da análise do código-fonte Lua - mecanismo de implementação gc [versão detalhada] (1)

Os parâmetros acima controlarão collectgarbagealguns parâmetros no modo incremental. O modo incremental usa o método mark-and-sweep, o que significa marcar primeiro e depois processar. Simplesmente falando, o método de marcação de três cores é usado para colocar todos os objetos na estrutura em árvore , e o relacionamento pai-filho pode usar uma lista vinculada e um método de inserção de cabeçalho para adicionar elementos.
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

No estado inicial, todas as cores dos nós são brancas. Branco representa nenhuma referência
Insira a descrição da imagem aqui
. Agora o relacionamento de referência é como mostrado na imagem acima, em seguida, percorra o relacionamento de referência começando no nó raiz e pinte os nós na lista vinculada. O nó 1 tem uma referência, então Insira a descrição da imagem aqui
pinte-o de cinza, insira seu vá para a lista vinculada cinza e
Insira a descrição da imagem aqui
continue A criança nº 1 tem uma referência ao nº 4. Cor nº 1 preto e adicione-o à lista vinculada. Em seguida, cor nº 4 cinza e adicione-o à lista vinculada.

Em seguida, repita o processo acima: o número 4 é preto e sai da lista vinculada, e 789 é cinza e entra na lista vinculada. Execute em sequência até que não haja mais nós na lista vinculada cinza, então todos os nós referenciados serão coloridos em preto.

A última etapa é o processo de limpeza. O nó de varredura percorrerá sequencialmente a lista vinculada rootgc e todos os nós brancos serão propostos. Se um nó branco for referenciado repentinamente antes da limpeza, o nó será colorido com uma cor protetora branca e será não ser excluído. Após finalizar, configure todos os nós pretos para brancos para facilitar a próxima limpeza.

Modelo geracional

collectgarbage("generational",20,200)
1,minor
    比例数,相对于上次major回收增长的比例,达到即执行minor , 默认20% 最大200%
2), major 
    比例数,内存使用增长比例达到就执行回收,默认100,最大1000

Os parâmetros acima irão controlar collectgarbagealguns parâmetros no modo iterativo.No modo GC geracional, o coletor de lixo freqüentemente realiza pequenas coletas de lixo, verificando a cada vez os objetos criados mais recentemente para limpar o lixo neles, em vez de verificar todos os objetos. Se a memória ainda exceder o limite após um GC tão pequeno, a execução do programa será pausada e percorrerá todos os objetos do GC.


__gc

A metatabela também fornece um metamétodo para gc __gc. A função definida pelo metamétodo é oficialmente chamada de finalizador. Por enquanto, é chamada de "destruidor" no Zhihu (verifique recentemente a entrada GC de C#, oficialmente adotada pela Microsoft). é terminador ). Quando este objeto com metamétodos definidos for reciclado pelo gc, ele executará a função no finalizador. Usando este metamétodo, podemos chamar a função finalizador quando certos objetos são limpos ou ressuscitar certos objetos para evitar que sejam limpos.

Exemplo 1:

t = {
    
    name = "zhangsan"}
setmetatable(t,{
    
    __gc = function (t)
    print(t.name)
end})
t = nil
--调用t的析构函数,打印zhangsan

No Exemplo 1, zhangsan é impresso, mas t é limpo pelo gc. O processo real é: gc começa a limpar o objeto -> usa o finalizador, imprime t.name (embora t=nil, foi brevemente ressuscitado pelo finalizador , e ele morrerá novamente após executar o terminador)->gc cleanup

Se um objeto não adicionar o metamétodo __gc ao configurar a metatabela, mas adicioná-lo após a criação da metatabela, então o objeto não será capaz de acionar o metamétodo __gc quando for reciclado.

t = {
    
    name = "zhangsan"}
mt = {
    
    }
setmetatable(t,mt)
--先设置元表,再为元表添加__gc元方法
mt.__gc = function (t)
    print(t.name)
end
t = nil
--不会输出任何值(未执行终结器)

Como o finalizador precisa acessar o objeto reciclado, Lua precisa ressuscitar o objeto. Normalmente esta ressurreição dura pouco, e a memória ocupada por este objeto será liberada durante o próximo GC. Entretanto, se o finalizador armazenar o objeto em algum local global (como uma variável global), essa ressurreição se tornará permanente.

t = {
    
    name = "zhangsan"}
setmetatable(t,{
    
    __gc = function (t)
    print(t.name)
    a = t   --在析构函数中将它赋值给全局变量
end})
t = nil
collectgarbage()    --在此处要手动垃圾回收,否则由于下方还有语句不会执行gc,而a也就不会被赋值了,打印zhangsan
print(a.name)       --t引用的对象并未被回收(永久复活),打印zhangsan

tabela fraca tabela de referência fraca

E se você quiser salvar alguns objetos ativos? Só precisamos colocá-lo no array, mas uma vez que um objeto é adicionado ao array, ele não pode mais ser reciclado, porque mesmo que não seja referenciado em outro lugar, ele ainda está incluído no array!No entanto, podemos dizer explicitamente a Lua através da **tabela fraca** que as referências neste array não devem afetar a reciclagem deste objeto.

Referências fracas referem-se a referências que não são consideradas pelo coletor de lixo. Se todas as referências a um objeto forem referências fracas, então o coletor de lixo reciclará o objeto e excluirá essas referências fracas. A tabela de referência fraca é implementada no método de referência Lua Weak.

__modeSe uma tabela é uma tabela de referência fraca é determinado pelos campos da sua metatabela.Existem três situações, nomeadamente:

  • Referência fraca de chave: definida para __mode = "k"permitir que o coletor de lixo recupere suas chaves, mas não os valores.
  • Referência fraca de valor: ao definir __mode = "v", o coletor de lixo pode recuperar seu valor, mas não a chave. Também chamada de tabela efêmera, os valores só podem ser acessados ​​se suas chaves estiverem acessíveis. Pois quando sua chave estiver inacessível, o valor também será retirado da tabela pelo coletor de lixo.
  • As chaves e valores são todas referências fracas: ao definir __mode = "kv", as chaves e valores podem ser reciclados.

Ressalta-se que em qualquer caso, assim que tablea chave ou valor for reciclado, todo o par chave-valor será tabledele .

O conteúdo a seguir foi extraído da referência fraca dos fundamentos de Lua

Lua usa um mecanismo de gerenciamento de memória com coleta automática de lixo, mas às vezes Lua não consegue determinar corretamente se um objeto precisa ser destruído, fazendo com que alguns objetos que precisam ser destruídos sempre existam, causando vazamentos de memória.

a = {
    
    }
key = {
    
    }
print(a[key])
a[key] = 1
print(a[key])
key = {
    
    }
print(a[key])
a[key] = 2
collectgarbage()
for k,v in pairs(a) do
    print(k, v)
end
输出:
nil
1
nil
table: 00000000006da000	1
table: 00000000006da380	2

O 1 que deveria ter sido destruído não foi destruído. Embora a[key] fosse nula após key={}, ainda obtivemos 1 quando atravessamos, indicando que não foi destruído. Isso ocorre porque esta a[key] é armazenada em uma matriz, e os pares chave-valor na matriz não podem ser excluídos pelo GC, mesmo que estejam vazios, e esta situação levará a vazamentos de memória. Portanto, para evitar esta situação, podemos usar referências fracas para informar o mecanismo de GC: Embora seja um array, os valores-chave vazios nele podem ser excluídos!

a = {
    
    }
b = {
    
    __mode = "k"}
setmetatable(a,b)
key = {
    
    }
a[key] = 1
key = {
    
    }
a[key] = 2
collectgarbage()
for k,v in pairs(a) do
    print(v)
end
输出:
2

Acho que você gosta

Origin blog.csdn.net/milu_ELK/article/details/131984125
Recomendado
Clasificación