垃圾回收教程

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
编辑 · 历史
最后编辑于 2010 年 7 月 8 日 上午 7:14 GMT (差异)