目录

Lua初探-垃圾回收


Garbage Collection
  • Lua实行自动内存管理。这意味着你不需要担忧为一个新对象分配内存或者当这个对象不再需要时进行内存的释放。Lua通过运行一个垃圾收集去收集所有的无用的对象(无用对象一般是指Lua不能够在访问该对象)来进行自动化的内存管理。所有的内存使用都是通过Lua去自动化控制的,对象包括:string、tables、userdata、functions、threads、internal structures,等等

  • Lua实现了一个增量的标记和扫描收集器。该收集器使用两个成员去控制垃圾回收的生命周期:垃圾回收暂停和垃圾回收步骤倍增器。这两个成员都是使用百分值作为单位(一个100的值意味着在内部的值是1)。

  • 垃圾收集暂停器控制在开始一个新的收集周期时等待多长时间。较大的值能使收集器不那么有侵略性。小于100的值意味着收集行为将不等待而直接开始一个新的收集周期。一个200的值意味着收集行为的启动需要等待到总内存被使用加倍时。

  • 垃圾收集器步骤乘法器控制收集器相对于内存分配的相对速度。大的值能使收集器更具侵略性但也增加了每个增量步骤的大小。你不应该使用小于100的值,因为他们将使收集器太慢并且可能造成收集器永远无法完成一个周期。默认值是200.意味着收集器以两倍的内存分配速度进行运行。

  • 如果你设置乘法器到一个非常大的值(大于程序可能使用的最大字节数的10%),收集器的行为就像一个世界级收集器,之后如果你设置暂停器到200.收集器的行为又像老版本的Lua。一般以Lua以两倍的内存分配速度去完成收集。

  • 你可以通过在C中调用lua_gc 或者在Lua中调用collectgarbage去直接控制收集器。

Garbage-Collection Metamethods
  • 对于full userdata 和tables,你可以使用C API 为其设置一个垃圾收集器元方法。该方法会在对象终结的时候被调用,通过该特性,你可以在Lua的垃圾回收时去处理外部资源的管理,如关闭文件,网络或者数据库连接以及释放自己的内存。

  • 对于一个被终结的table或者userdata的对象。你必须最终标识它,通过设置key为__gc的元方法中的字段来标识一个对象终结了。注意,如果你用一个__gc字段设置了一个元表,但随后你在该元表上创建字段,该元表将不被标识为终结。

  • 当一个被标识的对象变成垃圾,它不会立即被垃圾收集器回收。Lua会将它加入一个列表,在后面Lua通过该列表对其进行回收。对于在该列表中的每个对象,Lua会检测对象的__gc元方法,如果它是一个方法,也就是有设置,Lua将以该对象为一个参数调用它。如果原方法不是一个方法,Lua就会忽略它。

  • 在每次垃圾收集循环后,在生命周期中收集的被终结的对象们将被逆序地被标识为终结。第一个终结的对象在回收代码中会被最后标识。每个终结对象回收可能发生在执行代码的任意时间点。

  • 因为正在收集的对象仍然被终结者使用,这个对象(以及只能通过它访问的其他对象)必须由Lua复活。通常,这种复活是暂时的,并且在下一个垃圾收集周期中释放对象存储器。然而,如果终结者在一些全局的地方存储它,此时此时复活是常驻的。此外,如果终结器再次标记最终化的终结对象,则将在下一个无法访问对象的循环中再次调用其终结器。 在任何情况下,仅在GC循环中释放对象存储器,其中对象不可到达且未标记为完成。

  • 当你关闭一个状态(参见lua_close)时,Lua按照标记的相反顺序调用标记为完成的所有对象的终结符。如果任何终结器在该阶段标记要收集的对象,则这些标记无效。