本页面是关于为 Lua 5.1.4 创建一个紧急垃圾收集器补丁。请注意,LuaFiveTwo 已将紧急垃圾收集器列为其包含的功能之一。此补丁的工作与可能包含在 LuaFiveTwo 中的紧急垃圾收集器是分开进行的。紧急 GC 补丁使得在内存分配失败后安全地调用 Lua 垃圾收集器成为可能。这允许垃圾收集器释放一些内存,以便可以重试失败的分配。该补丁还增加了对设置 Lua 脚本可以分配的内存量的限制的支持。
文件
[下载紧急 GC 补丁(针对 5.1.4 版本 6)]
[用于压力测试紧急垃圾回收的程序。]
额外的内存优化功能。
这些功能已包含在紧急 GC 补丁中。它们可以在没有紧急 GC 补丁的情况下使用。
- 内部字符串哈希表的重定义需要分配一个额外的哈希表。对于需要在极少量内存(64-256kbytes)下运行的脚本,当脚本内存不足(仅剩 1-2kbytes)时,这可能会导致“内存不足”错误。我有一个想法,可以在不分配额外哈希表的情况下原地重定义哈希表。唯一的缺点是哈希表中的某些字符串会被删除并重复添加。所以这种方法将使用更多的 CPU 时间来节省一些额外的内存使用。[字符串表补丁,针对 5.1.3]
- Lua 表的哈希部分与字符串哈希表存在相同的重定义问题。重定义表的哈希部分需要更多的工作,因为重定义代码更复杂。[哈希部分补丁,针对 5.1.3]
关于 Lua 垃圾收集器如何工作的说明
免责声明:这是我第一次接触垃圾收集器,因此其中一些内容可能不正确。欢迎进行更正/清理。--RobertGabrielJakabosky
“在进行此补丁的工作时,我不得不学习 Lua 的垃圾收集器是如何工作的。我写下这些是为了以后如果我需要修复收集器中的更多错误时能有所帮助,并且我希望这些信息也能帮助其他对 Lua 垃圾收集器工作原理感兴趣的人。” --RobertGabrielJakabosky
简单描述
Lua 垃圾收集器是一个标记-清除收集器。收集器在其每个收集周期中运行两个主要阶段:标记和清除。在标记阶段,收集器遍历 Lua 堆栈并进入表以标记找到的活动值。接下来,清除阶段将遍历所有可收集值的列表,并释放找到的所有死值。
详细描述
所有可收集类型的对象都有一个“marked”位字段。这些位定义如下(摘自头文件“lgc.h”)
- 位 0 - 对象为白色(类型 0)
- 位 1 - 对象为白色(类型 1)
- 位 2 - 对象为黑色
- 位 3 - 对于 userdata:已完成 finalization
- 位 3 - 对于表:具有弱键(注意此位有两种不同的含义,一种用于 userdata,一种用于表)
- 位 4 - 对于表:具有弱值
- 位 5 - 对象是固定的(不应被收集)
- 位 6 - 对象是“超级”固定的(仅主线程)
垃圾收集器跟踪当前白色(类型 0 或 1),具有另一种白色的对象是死对象,可以在清除状态下被收集。对象的颜色由前 3 位(0、1、2)的哪些位被设置来定义
- 如果设置了两个白色位(0、1)中的一个,并且黑色位被清除,则它是白色的。白色对象应该只使用一个白色位。
- 如果所有三个颜色位(0、1、2)都被清除,则它是灰色的。
- 如果黑色位被设置,而两个白色位都被清除,则它是黑色的。
垃圾收集器状态(每个收集周期按此顺序通过这些状态)
- GCSpause - 收集周期的开始。在此状态下,所有对象都应标记为当前白色。主 `lua_State`、全局表、注册表和元表被标记为灰色并添加到灰色列表中。状态现在变为 GCSpropagate。
- GCSpropagate - 灰色列表中的每个对象都被移除并标记为黑色,然后它引用的任何白色(类型 0 或 1)对象都被标记为灰色并添加到灰色列表中。一旦灰色列表为空,当前白色就会切换到另一种白色。所有标记为旧白色类型的对象现在都是死对象。状态现在变为 GCSsweepstring。
- GCSsweepstring - 检查内部字符串哈希表中每个字符串的颜色。如果颜色与旧白色类型匹配,则该字符串是死的并被释放。如果颜色与当前白色(新创建的字符串)匹配,或者它是灰色的(其他对象引用它),那么它是活的,并且其颜色将被重置为当前白色。一旦所有字符串都被检查完毕,状态就会变为 GCSsweep。
- GCSsweep - 与 GCSsweepstring 状态类似,检查全局 rootgc 列表(此列表包含除字符串外的所有对象)中每个对象的颜色。死对象被释放并从 rootgc 列表中移除。活对象被重置为当前白色。一旦所有对象都经过检查,状态就会变为 GCSfinalize。
- GCSfinalize - 此状态将通过运行其 `__gc` 元方法来完成所有死 userdata 对象的 finalization。一旦所有死 userdata 对象都已完成 finalization,状态就会变为 GCSpause,从而完成一次垃圾收集器周期。
--RobertGabrielJakabosky
另请参阅
RecentChanges · preferences
编辑 · 历史
最后编辑于 2010 年 12 月 8 日上午 1:05 GMT (差异)