[Lua Study Notes] Lua Advanced - Garbage Collection

Insert image description here
According to Teacher Tang's course, it was supposed to teach about built-in libraries, but think about it, you can read documents, ctrl + left click can also read annotations, and the most important thing is that many of the methods of built-in libraries are available in most languages. In fact, take a look You will understand. So let’s focus on garbage collection.

Most of the following content is excerpted from [Lua] Detailed explanation of garbage collection , Lua source code analysis - gc implementation mechanism [detailed version] (1) , please read the article in the link


GC

If you come into contact with Lua from Unity, you should know that there is also a GC mechanism in C#. Virtual machines are used in most object-oriented languages, and the Mono virtual machine is also used in Unity. Our code is in the virtual memory of the virtual machine. In the virtual machine, the code must be converted into an instruction set, compiled into bytecode, and finally the bytecode translated instruction set is used on each platform to achieve cross-platform implementation.

Since the memory space occupied by the object is stored in virtual memory, it will not affect physical memory. When physical memory needs to call the object, the virtual memory block will be assigned to the physical memory. If a virtual memory block is not referenced by physical memory for a long time, then the memory it occupies should be released. This is GC (garage collect)

According
to the official description, Lua can automatically manage memory through the GC mechanism and eliminate dead objects. The types of these objects include: string, tables, userdata, function, threads, internal structures, etc.

Objects that are considered dead will no longer be accessed in the program (but finalizers can resurrect these dead objects). What the GC thinks is dead is different from what the programmer thinks. The GC thinks that it is dead if it is inactive for a long time. If an object is considered dead, it can no longer be accessed normally.

By using functions collectgarbageor defining metamethods __gc, we can directly use or override the gc mechanism.


Auxiliary garbage collection

Although automatic garbage collection is applicable most of the time, in some special cases we still need to determine the objects and timing of garbage collection ourselves. To this end, the Lua language provides a way to assist in garbage collection.

  • collectgarbage function: allows controlling the step size of the garbage collector
  • Destructor (recently check the GC entry of C#, Microsoft’s official Chinese name is called finalizer ) (finalizer): allows the collection of external objects that are not under the direct control of the garbage collector.
  • Weak reference table (weak table): allows the collection of objects in Lua that can also be accessed by programs (especially null key values ​​​​in the table)

collectgarbage

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

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

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

Each time garbage collection takes up a lot of memory, so use it as little as possible, and don't use it automatically if you can do it manually.

collectgarbageTwo recycling modes are provided, namely incremental mode and generational mode.

incremental mode

In incremental mode, each gc cycle uses the mark-and-sweep method to gradually mark and collect garbage. The GC and the interpreter run together alternately (Lua5.1 and later, there is no need to stop the running of the main program). Whenever When the interpreter allocates a certain amount of memory, the garbage collector also performs a step. Each GC cycle consists of four phases, namely mark, cleaning, sweep and finalization:

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

Most of the following content is excerpted from Lua source code analysis - gc implementation mechanism [detailed version] (1)

The above parameters will control collectgarbagesome parameters in the incremental mode. The incremental mode uses the mark-and-sweep method, which means marking first and then processing. Simply speaking, the three-color marking method is used to put all objects in Tree structure, and the parent-child relationship can use a linked list and head insertion method to add elements.
Insert image description here
Insert image description here

In the initial state, all node colors are white. White represents no reference
Insert image description here
. Now the reference relationship is as shown in the picture above, then traverse the reference relationship starting from the root node, and color the nodes in the linked list. Node Insert image description here
1 has a reference, so color it gray, insert its head into the linked list gray and
Insert image description here
continue Child No. 1 has a reference to No. 4. Color No. 1 black and add it to the linked list. Then color No. 4 gray and add it to the linked list.

Then repeat the above process. No. 4 is colored black and comes out of the linked list, and 789 is colored gray and entered into the linked list. Execute in sequence until there are no more nodes in the gray linked list, then all referenced nodes will be colored black.

The last step is the cleanup process. The sweep node will sequentially traverse the rootgc linked list, and all white nodes will be proposed. If a white node is suddenly referenced before clearing, the node will be colored with a protective color of white and will not be deleted. After finishing, set all black nodes to white to facilitate next cleaning.

Generational model

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

The above parameters will control collectgarbagesome parameters in the iterative mode. In the generational GC mode, the garbage collector frequently performs small garbage collections, scanning from the most recently created objects each time to clean up the garbage in them, instead of scanning all object. If the memory still exceeds the limit after such a small GC, it will pause the running of the program and traverse all objects for GC.


__gc

The metatable also provides a metamethod for gc __gc. The function defined by the metamethod is officially called finalizer. For the time being, it is called "destructor" on Zhihu (recently check the GC entry of C#, officially adopted by Microsoft) The Chinese name is terminator ). When this object with metamethods defined is recycled by gc, it will execute the function in the finalizer. Using this metamethod, we can call the finalizer function when certain objects are cleaned up, or resurrect certain objects to prevent them from being cleaned up.

Example 1:

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

In Example 1, zhangsan is printed, but t is cleaned up by gc. The actual process is: gc starts cleaning up the object -> uses the finalizer, prints t.name (although t=nil, it was briefly resurrected by the finalizer, and It will die again after executing the terminator)->gc cleanup

If an object does not add the __gc metamethod when setting up the metatable, but adds it after the metatable is created, then the object will not be able to trigger the __gc metamethod when it is recycled.

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

Because the finalizer needs to access the recycled object, Lua needs to resurrection the object. Usually this resurrection is short-lived, and the memory occupied by this object will be released during the next GC. However, if the finalizer stores the object in some global location (such as a global variable), then this resurrection becomes permanent.

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

weak table weak reference table

What if you want to save some active objects? We just need to put it into the array, but once an object is added to the array, it can no longer be recycled, because even if it is not referenced elsewhere, it is still included in the array!However, we can explicitly tell Lua through the **weak table** that the references in this array should not affect the recycling of this object.

Weak references refer to references that are not considered by the garbage collector. If all references to an object are weak references, then the garbage collector will recycle the object and delete these weak references. The weak reference table is implemented in Lua Weak reference method.

__modeWhether a table is a weak reference table is determined by the fields of its metatable . There are three situations, namely:

  • Key weak reference: Set to __mode = "k"allow the garbage collector to reclaim its keys, but not the values.
  • Value weak reference: By setting __mode = "v", the garbage collector is allowed to reclaim its value, but not the key. Also called an ephemeron table, values ​​can only be accessed if its keys are accessible. Because when its key is inaccessible, the value will also be removed from the table by the garbage collector.
  • The keys and values ​​​​are all weak references: by setting __mode = "kv", the keys and values ​​​​are allowed to be recycled.

It should be emphasized that in any case, as soon as tablethe key or value is recycled, the entire key-value pair will be removed tablefrom it .

The following content is excerpted from the weak reference of Lua basics

Lua uses a memory management mechanism with automatic garbage collection, but sometimes Lua cannot correctly determine whether an object needs to be destroyed, causing some objects that need to be destroyed to always exist, causing memory leaks.

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

The 1 that should have been destroyed was not destroyed. Although a[key] was nil after key={}, we still got 1 when we traversed, indicating that it was not destroyed. This is because this a[key] is stored in an array, and the key-value pairs in the array are not allowed to be deleted by GC even if they are empty, and this situation will lead to memory leaks. Therefore, in order to avoid this situation, we can use weak references to tell the GC mechanism: Although it is an array, the empty key values ​​​​in it can be deleted!

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

Guess you like

Origin blog.csdn.net/milu_ELK/article/details/131984125