Lua五:”collectgarbage”、 弱引用table、析构器「建议收藏」

2022-09-06 16:07:32 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

Lua具有自动内存回收机制,但是垃圾收集器只能回收那些它认为是垃圾的东西,不会回收那些用户认为是垃圾的东西。比如将一个对象放在一个数组中但没有用时,它就无法被回收,这是因为即使当前没有其他地方在使用它,但数组仍引用着它,除非用户告诉Lua这项引用不应该阻碍此对象的回收,否则Lua是无从得知的。

Lua垃圾回收函数collectgarbage,这个函数是垃圾回收机制的一个通用接口,其第一个参数是字符串,代表操作类型,第二个参数只有某些操作有,是该操作所需要的参数。其原型:collectgarbage ([opt [, arg]])

操作类型:

  • “collect”:执行一个完整的垃圾回收周期,这是一个默认的选项。
  • “stop”:停止垃圾收集器(如果它在运行),直到再次使用操作为”restart”的圾回收函数collectgarbage。
  • “restart”:将重新启动垃圾收集器(如果它已经停止)。
  • “count”:返回当前使用的的程序内存量(单位是Kbytes)。
  • “step”:执行垃圾回收的步骤,这个步骤的大小由参数arg(较大的数值意味着较多的步骤)以一种不特定的方式来决定,如果你想控制步骤的大小,你必须实验性的调整参数arg的值,如果这一步完成了一个回收周期则函数返回true。
  • “setpause”:第二个参数pause 用于控制垃圾收集器在一次收集完成后等待多久再开始新的一次收集。当值为零时表示 Lua语言在上一次垃圾回收结束后立即开始一次新的收集。当值为200%时表示在重启垃圾收集器前等待内存使用翻番。如果想使消耗更多的CPU时间换取更低的内存消耗,那么可以把这个值设得小一点。通常,我们应该把这个值设在О到200%之间。
  • “setstepmul”:参数stepmul控制对于每分配1KB内存,垃圾收集器应该进行多少工作。这个值越高,垃圾收集器使用的增量越小。一个像100000000%一样巨大的值会让收集器表现得像一个非增量的垃圾收集器。默认值是 200%。低于100%的值会让收集器运行得很慢,以至于可能一次收集也完不成。

两个参数pause和stepmul控制着垃圾收集器的角色。任何垃圾收集器都是使用CPU时间换内存空间。在极端情况下,垃圾收集器可能根本不会运行。但是,不耗费CPU时间是以巨大的内存消耗为代价的。在另外一种极端的情况下,收集器可能每进行一次赋值就得运行一次完整的垃圾收集。程序能够使用尽可能少的内存,但是是以巨大的CPU消耗为代价的。pause 和stepmul的默认值正是试图在这两个极端之间找到的对大多数应用来说足够好的平衡点。

选项setpause的使用方法:collectgarbage(“setpause”, 200),表示当收集器在总使用内存数量达到上次垃圾收集时的两倍时再开启新的收集周期。

选项setstepmul的使用方法:collectgarbage(“setstepmul”, 200),表示垃圾收集器的运行速度是内存分配的2倍,如果此值小于100可能会导致垃圾回收不能形成完整的周期。

table中有key和value,这两者都可以包含任意类型的对象。通常,垃圾收集器不会回收一个可访问table中作为key或value的对象。也就是说,这些key和value都是强引用,它们会阻止对其所引用对象的回收。在一个弱引用table中,key和value是可以回收的。

弱引用table(weak table)是用户用来告诉Lua一个引用不应该阻碍对该对象的回收。所谓弱引用,就是一种会被垃圾收集器忽视的对象引用。如果一个对象的引用都是弱引用,该对象也会被回收。

弱引用table有3种类型:1、具有弱引用key的table;2、具有弱引用value的table;3、同时具有弱引用key和value的table;

table的弱引用类型是通过其元表中的__mode字段来决定的。这个字段的值应为一个字符串:如果包含’k’,那么这个table的key是弱引用的;如果包含’v’,那么这个table的value是弱引用的;

弱引用table的一个例子,这里使用了collectgarbage函数强制进行一次垃圾收集:

代码语言:javascript复制
 1 a = {}
 2 setmetatable(a, {__mode='k'})
 3 
 4 key = {}
 5 a[key] = 'key1'
 6 
 7 key = {}
 8 a[key] = 'key2'
 9 
10 collectgarbage()

该段代码“collectgarbage()”运行前,表a同时存在key为{}和value为’key1’和’key2’的对象,“collectgarbage()”运行后,只存在key为{}和value为’key2’的对象。

析构器_gc简单来说,就是当一个table的元表中存在_gc时,就会在这个lua table被gc释放掉之前,调用的函数。不过,在5.2之前,_gc只能用在userdata中,而5.2及5.2之后,table也可以用__gc了。

代码语言:javascript复制
 1 function class(name, super)
 2    ...
 3     -- 析构函数
 4     if cls.dtor then
 5         cls.dtor = function(self) end
 6     end
 7 
 8     cls.__meta = {__index = cls, __gc = function(self) self:dtor() end}
 9     cls.new = function(...)
10         local obj = setmetatable({}, cls.__meta)
11         obj:ctor(...)
12         return obj 
13     end
14     return cls
15 end

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/154976.html原文链接:https://javaforall.cn

0 人点赞