优化垃圾回收

lua-users home
wiki

简介

如果系统生成了大量对象,垃圾回收可能会导致性能问题。本页讨论了相关问题以及避免问题的思路。

最小化创建的对象

问题:基本上我想最小化临时内存的分配量,以便减少 GC 被调用的频率(也许还能减少每次 GC 的影响?)。有人能就这个话题给出一些提示吗?例如,如果我在函数 A 中声明了局部变量,那么每次调用 A 时局部变量都会分配内存吗?

(ET) 不会。局部变量保存在堆栈中,不会影响 GC。这些结构会创建一个新的垃圾回收对象

每个字符串都会创建一个新对象。Lua 有唯一的字符串,这意味着每个可能的字符串在 Lua 中只存在一次。如果出现一个新字符串,Lua 首先会检查它是否已经存在于字符串池中。如果存在,则使用对该旧字符串的引用。如果不存在,则创建一个新的字符串对象并将其放入字符串池中。GC 检查字符串池中未使用的字符串并释放它们。因此,创建大量唯一字符串会占用 GC。例如,这在 GC 方面很糟糕
for i=1,100 do  x="foo"..tostring(i)  end  -- 100 new strings
注意:代码段保存对字符串常量的引用(如上面的 "foo")。因此,只要函数存在,字符串就会存在于字符串池中;它不需要每次执行函数时都创建。

每次执行表构造函数时,都会创建一个新表。如果可能,请尝试重用表。你甚至可以创建和使用 newtable/freetable 函数来管理一组未使用的表。这样,你就可以获得旧式内存管理的表,但也会遇到旧式的问题 ;-)

执行函数语句会创建一个闭包(注意:不是调用函数,而是执行函数语句!)。通常对 GC 影响不大,但如果在循环中包含函数语句,你可能会创建很多垃圾。例如:
for i=1,100 do  foo(function() end)  end  -- bad for GC
创建 100 个函数闭包。

每次调用可变参数函数时,都会为省略号创建一个表(存储在 'arg' 中)。(注意:从 Lua 5.2 开始不再适用,或者如果使用 LuaJIT。)

在 Lua 4.0(以及 3.x)中,userdata 对象的处理方式类似于字符串。如果指针值和标签相等,则它们相等。Lua5 怎么样?

它们加载/编译新的代码,并创建字符串和(GC 管理的)代码段。

释放局部变量

问题(延续上面): 那么,当您退出函数时,任何局部字符串或表都会被释放吗?

变量是用来存储对象的(实际上,除了数字之外,它只保存指向对象的指针)。存储的对象是数字、表还是其他任何东西,对变量来说都没有关系。局部变量本身不是垃圾回收对象。因此,您可以使用它们而无需创建中间对象。我认为,这就是最初发帖者所指的意思。

“因此,您可以使用它们而无需创建中间对象。” 这需要澄清吗?变量本身不会创建 GC 对象,但它的值可能会。您可以使用引用其他现有对象的局部变量,而无需创建需要收集的对象。但是,您不能创建新的局部对象,而无需创建稍后需要收集的对象。

关于存储在局部变量中的对象:当局部变量不再活动时,GC *可能* 会收集存储在那里的对象。对象的实际释放与函数范围或变量生命周期无关。GC 在特定时间运行,并释放所有不再被任何 L 访问的对象。

[*1] strsub 存在于 Lua 4 中,而不是 Lua 5 中。


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2014 年 4 月 18 日下午 7:12 GMT (差异)