垃圾回收教程

lua-users home
wiki

不可达对象

在像 C 和 C++ 这样的语言中,我们在运行时创建的对象(例如使用 malloc()new)必须显式删除。内存泄漏是由于对象被分配、丢失且从未释放而导致的。可以编写内存跟踪系统,为我们分配内存并知道我们何时不再需要它。一些语言内置了此功能,包括 Lua。

有各种方法来跟踪哪些内存对象不再需要。一旦应用程序的变量不再引用某个对象,该对象就被认为是不可达的。不再可达的对象将变得可删除,并且是自动处理或垃圾回收的候选者。

在以下示例中,我们创建了一些 Lua 对象并将它们分配给变量。如果我们将其他值分配给变量,并且没有其他变量引用先前的对象,它们将变得不可达。如果没有垃圾回收,这会导致内存泄漏。例如:

> t = { this="table"; 1,2,3 }  -- construct a table and assign it to "t"
> t = nil                      -- set "t" to nil and the table becomes unreachable
>
> s = "a string"               -- create string variable
> s = "another string"         -- when set to another value the old value becomes unreachable

简单的收集算法

有各种类型的收集器,以及与垃圾回收相关的许多术语 [1]。最简单的收集算法之一是引用计数。在这里,我们只在分配的每个对象中保留一个计数,表示引用(或使用)它的对象数量。如果引用另一个对象的物体数量降至零,它将变得不可达(并且未使用),并且可以释放。这方面的一个小问题是循环引用,其中对象 A 引用对象 B,而 B 引用 A。只要其他对象引用 A 和/或 B,这就可以了,但当它们不再这样做时,A 和 B 将形成一个岛屿。由于循环引用,它们现在成为一组不可达且相互永久的对象。除非扩展引用计数收集算法,否则该岛屿永远不会被释放。例如:

> a = {}
> b = {}
> a['other'] = b
> b['other'] = a   -- now we have a cyclic reference
> a,b = nil,nil    -- oh dear, we don't have a reference to the 2 tables now
>                  -- there are two tables which are unreachable

标记和清除

为了从上述算法中消除岛屿,我们可以遍历系统中的所有变量,并查看它们引用了哪些对象。如果变量发现某些对象不可达,我们可以对其进行垃圾回收。这种算法称为标记和清除,即我们标记所有可达对象并清除剩余的对象。Lua 专门使用标记和清除垃圾回收算法。这样做的好处是我们不必对对象进行引用计数,因此不会出现循环引用问题。缺点是该算法需要时间来处理,并且在实时应用程序中可能是一个问题。

注意:如果我们要分布式处理标记和清除收集算法,使其不一次完成,那么它对主机系统将更加透明。这称为增量垃圾回收。此更改是在 Lua 版本 5.1 中进行的。

控制和状态

Lua 提供了一些函数来控制和查询垃圾回收的状态。更多细节请参见 CoreFunctionsTutorial

更多阅读

参见参考手册第 2.10 节 [3]

维基上的其他页面更详细地介绍了 Lua 中的垃圾回收。以下建议阅读


RecentChanges · preferences
edit · history
最后编辑于 2010 年 7 月 8 日下午 1:14 GMT (diff)