[Notas de estudio de Lua] Lua Advanced - Recolección de basura

Insertar descripción de la imagen aquí
Según el curso del profesor Tang, se suponía que enseñaría sobre bibliotecas integradas, pero piénselo, puede leer documentos, Ctrl + clic izquierdo también puede leer anotaciones, y lo más importante es que muchos de los métodos integrados. En las bibliotecas están disponibles en la mayoría de los idiomas. De hecho, échale un vistazo y lo entenderás. Así que centrémonos en la recolección de basura.

La mayor parte del siguiente contenido está extraído de [Lua] Explicación detallada de la recolección de basura , Análisis del código fuente de Lua: mecanismo de implementación de gc [versión detallada] (1) , lea el artículo en el enlace


GC

Si entra en contacto con Lua de Unity, debe saber que también existe un mecanismo GC en C #. La máquina virtual se usa en la mayoría de los lenguajes orientados a objetos y la máquina virtual Mono también se usa en Unity. Nuestro código está en la memoria virtual de la máquina virtual, en la máquina virtual, el código debe convertirse en un conjunto de instrucciones, compilarse en código de bytes y, finalmente, el conjunto de instrucciones traducido del código de bytes se utiliza en cada plataforma para lograr una implementación multiplataforma.

Dado que el espacio de memoria ocupado por el objeto se almacena en la memoria virtual, no afectará la memoria física. Cuando la memoria física necesita llamar al objeto, el bloque de memoria virtual se asignará a la memoria física. Si la memoria física no hace referencia a un bloque de memoria virtual durante mucho tiempo, entonces se debe liberar la memoria que ocupa, esto es GC (recolección de garaje).

Según
la descripción oficial, Lua puede administrar automáticamente la memoria a través del mecanismo GC y eliminar objetos muertos. Los tipos de estos objetos incluyen: cadenas, tablas, datos de usuario, funciones, subprocesos, estructuras internas, etc.

Ya no se podrá acceder a los objetos que se consideran muertos en el programa (pero los finalizadores pueden resucitar estos objetos muertos). Lo que el GC piensa que está muerto es diferente de lo que piensa el programador. El GC piensa que está muerto si está inactivo durante mucho tiempo. Si un objeto se considera muerto, ya no se puede acceder a él normalmente.

Al usar funciones collectgarbageo definir metamétodos __gc, podemos usar o anular directamente el mecanismo gc.


Recolección auxiliar de basura

Aunque la recolección automática de basura es aplicable la mayor parte del tiempo, en algunos casos especiales aún necesitamos determinar nosotros mismos los objetos y el momento de la recolección de basura. Con este fin, el lenguaje Lua proporciona una forma de ayudar en la recolección de basura.

  • Función Collectgarbage: permite controlar el tamaño del paso del recolector de basura.
  • Destructor (verifique recientemente la entrada GC de C #, el nombre oficial chino de Microsoft se llama finalizador ) (finalizador): permite la recolección de objetos externos que no están bajo el control directo del recolector de basura.
  • Tabla de referencia débil (tabla débil): permite la colección de objetos en Lua a los que también pueden acceder los programas (especialmente valores de clave nula en la tabla)

recoger basura

---@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 la recolección de basura ocupa mucha memoria, úsela lo menos posible y no la use automáticamente si puede hacerlo manualmente.

collectgarbageSe proporcionan dos modos de reciclaje, a saber, el modo incremental y el modo generacional.

modo incremental

En modo incremental, cada ciclo de gc utiliza el método de marcar y barrer para marcar y recolectar basura gradualmente. El GC y el intérprete se ejecutan juntos alternativamente (Lua5.1 y posteriores, no es necesario detener la ejecución del programa principal) Siempre que el intérprete asigna una cierta cantidad de memoria, el recolector de basura también realiza un paso. Cada ciclo de GC consta de cuatro fases: marcado, limpieza, barrido y finalización:

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

La mayor parte del siguiente contenido está extraído del análisis del código fuente de Lua: mecanismo de implementación de gc [versión detallada] (1)

Los parámetros anteriores controlarán collectgarbagealgunos parámetros en el modo incremental. El modo incremental utiliza el método de marcar y barrer, es decir, marcar primero y luego procesar. En pocas palabras, el método de marcado de tres colores se utiliza para colocar todos los objetos en la estructura de árbol. Y la relación padre-hijo puede usar una lista vinculada y un método de inserción de encabezado para agregar elementos.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

En el estado inicial, todos los colores de los nodos son blancos. El blanco no representa ninguna referencia
Insertar descripción de la imagen aquí
. Ahora la relación de referencia es como se muestra en la imagen de arriba, luego recorra la relación de referencia comenzando desde el nodo raíz y coloree los nodos en la lista vinculada. El nodo 1 tiene una referencia, así que coloréelo de gris, inserte Insertar descripción de la imagen aquí
su Dirígete a la lista enlazada en gris y
Insertar descripción de la imagen aquí
continúa. El niño número 1 tiene una referencia al número 4. Colorea el número 1 de negro y agrégalo a la lista enlazada. Luego colorea el número 4 de gris y agrégalo a la lista enlazada.

Luego repita el proceso anterior: el número 4 se colorea en negro y sale de la lista vinculada, y el 789 se colorea en gris y se ingresa en la lista vinculada. Ejecute en secuencia hasta que no haya más nodos en la lista enlazada gris, luego todos los nodos a los que se hace referencia se colorearán de negro.

El último paso es el proceso de limpieza. El nodo de barrido atravesará secuencialmente la lista enlazada de rootgc y se propondrán todos los nodos blancos. Si de repente se hace referencia a un nodo blanco antes de borrarlo, el nodo se coloreará con un color protector blanco y no se eliminará. Después de terminar, configure todos los nodos negros en blanco para facilitar la próxima limpieza.

Modelo generacional

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

Los parámetros anteriores controlarán collectgarbagealgunos parámetros en el modo iterativo. En el modo GC generacional, el recolector de basura realiza con frecuencia pequeñas recolecciones de basura, escaneando desde los objetos creados más recientemente cada vez para limpiar la basura que contienen, en lugar de escanear todos los objetos. Si la memoria aún excede el límite después de una GC tan pequeña, pausará la ejecución del programa y atravesará todos los objetos para la GC.


__gc

La metatabla también proporciona un metamétodo para gc __gc. La función definida por el metamétodo se llama oficialmente finalizador. Por el momento, se llama "destructor" en Zhihu (verifique recientemente la entrada GC de C #, adoptada oficialmente por Microsoft) El nombre chino es terminador ). Cuando gc recicla este objeto con metamétodos definidos, ejecutará la función en el finalizador. Usando este metamétodo, podemos llamar a la función finalizadora cuando se limpian ciertos objetos, o resucitar ciertos objetos para evitar que se limpien.

Ejemplo 1:

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

En el ejemplo 1, se imprime zhangsan, pero gc limpia t. El proceso real es: gc comienza a limpiar el objeto -> usa el finalizador, imprime t.name (aunque t = nil, el finalizador lo resucitó brevemente y morirá nuevamente después de ejecutar el terminador)->limpieza de gc

Si un objeto no agrega el metamétodo __gc al configurar la metatabla, pero lo agrega después de crear la metatabla, entonces el objeto no podrá activar el metamétodo __gc cuando se recicle.

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

Debido a que el finalizador necesita acceder al objeto reciclado, Lua necesita resucitar el objeto. Por lo general, esta resurrección es de corta duración y la memoria ocupada por este objeto se liberará durante la próxima GC. Sin embargo, si el finalizador almacena el objeto en alguna ubicación global (como una variable global), entonces esta resurrección se vuelve 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

tabla débil tabla de referencia débil

¿Qué pasa si desea guardar algunos objetos activos? Solo necesitamos colocarlo en la matriz, pero una vez que se agrega un objeto a la matriz, ya no se puede reciclar, porque incluso si no se hace referencia a él en ningún otro lugar, ¡todavía está incluido en la matriz!Sin embargo, podemos decirle explícitamente a Lua a través de la **tabla débil** que las referencias en esta matriz no deberían afectar el reciclaje de este objeto.

Las referencias débiles se refieren a referencias que no son consideradas por el recolector de basura. Si todas las referencias a un objeto son referencias débiles, entonces el recolector de basura reciclará el objeto y eliminará estas referencias débiles. La tabla de referencias débiles se implementa en el método de referencia débil de Lua.

__modeSi una tabla es una tabla de referencia débil está determinada por los campos de su metatabla . Hay tres situaciones, a saber:

  • Referencia débil de clave: configurada para __mode = "k"permitir que el recolector de basura recupere sus claves, pero no los valores.
  • Referencia débil de valor: al configurar __mode = "v", el recolector de basura puede reclamar su valor, pero no la clave. También llamada tabla de efemérides, solo se puede acceder a los valores si sus claves son accesibles. Porque cuando su clave es inaccesible, el recolector de basura también eliminará el valor de la tabla.
  • Las claves y los valores son todas referencias débiles: al configurarlas __mode = "kv", se permite que las claves y los valores se reciclen.

Cabe destacar que, en cualquier caso, tan pronto como tablese recicle la clave o el valor, se tableeliminará .

El siguiente contenido está extraído de la referencia débil de los conceptos básicos de Lua.

Lua utiliza un mecanismo de administración de memoria con recolección automática de basura, pero a veces Lua no puede determinar correctamente si un objeto debe destruirse, lo que hace que algunos objetos que deben destruirse existan siempre, lo que provoca pérdidas de memoria.

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

El 1 que debería haber sido destruido no fue destruido. Aunque una [clave] era nula después de la clave = {}, todavía obtuvimos 1 cuando atravesamos, lo que indica que no fue destruido. Esto se debe a que esta a [clave] está almacenada en una matriz, y GC no permite que los pares clave-valor de la matriz sean eliminados incluso si están vacíos, y esta situación provocará pérdidas de memoria. Por lo tanto, para evitar esta situación, podemos usar referencias débiles para indicarle al mecanismo de GC: ¡Aunque es una matriz, los valores clave vacíos que contiene se pueden eliminar!

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

Supongo que te gusta

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