我的Lua对象是否被收集?

时间:2013-01-25 23:23:15

标签: c++ memory-leaks lua

警告:

我现在确信问题是luatraverse脚本explained here不能像宣传的那样工作,并且找不到对象的所有引用。在我的示例中,我找到了引用对象的位置,从而阻止了它的收集,但脚本没有报告。

因此,这个问题的基本前提是有些缺陷的。

背景:

我正致力于在游戏Bitfighter中增强脚本引擎。我不相信内存正在被正确释放。所以我以下面的脚本的形式构建了一个测试。

它打印3列userdatas。第1列是我期望在其他地方使用的用户数据,因此应该被collectgarbage函数销毁。第2列和第3列是我认为不应该收集的对象,因为我正在处理它们。

问题:

第1列中的用户数据永远不会改变,所以我怀疑它没有被收集(第2列和第3列表现得如预期的那样)。为了进一步澄清这种情况,我使用this problem中提到的luatraverse脚本,这似乎证实只有一个对obj100的引用,它是存储在obj100中的。我尝试在运行countreferences之前添加一个赋值(本地x = obj100),并且正如预期的那样,countreferences报告了两次引用的对象。

问题:

1)我是否正确地解释了这个输出,并且obj100真的从未收集过吗?或者是否有可能一遍又一遍地重复使用相同的内存地址?

2)有没有比luatraverse脚本更好的方法来查看引用特定Lua对象的内容?

代码:

 -- Every 2 seconds, find two objects with ids 100 and 200, and print their addrs
 -- No reference is kept for object 100, so its userdata might change over time
 -- Object 200 is held by objHolder, so its userdata should remain constant

 -- Obj200 should remain constant over time; obj100 can vary.  
 -- objHolder should be constant, obviously

 local ltraverse = require("luatraverse")


 function printIds()
    local obj100 = levelgen:findObjectById(100)
    local obj200 = levelgen:findObjectById(200)
    print("Obj 100:" .. tostring(obj100) .. " Obj 200:" .. 
           tostring(obj200) .. " Held:" .. tostring(objHolder))


    print(ltraverse.countreferences(obj100))

    obj100 = nil
    obj200 = nil

    collectgarbage()
 end

 function main()
    -- levelgen:findObjectById is a local game command that
    -- creates a userdata for an object
    local obj100 = levelgen:findObjectById(100)
    objHolder    = levelgen:findObjectById(200)     -- not local, global

    assert(obj100)
    assert(objHolder)

    print("Column 1 can vary; 2 and 3 should be constant")
    print("=============================================")

    print("Obj 100:" .. tostring(obj100) .. " Obj 200:" .. 
         tostring(objHolder) .. " Held:" .. tostring(objHolder))

    obj100 = nil

    -- Run a function every 2 seconds
    Timer:scheduleRepeating(printIds, 2000)
 end 

输出:

 Column 1 can vary; 2 and 3 should be constant
 =============================================
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280

 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 ... and onward to infinity ...

1 个答案:

答案 0 :(得分:0)

我不认识Bitfighter,但我认为你在这里测量错误的东西:

这一行将创建一个新的Lua userdata对象,实际上指向真正的C ++(?)对象:

local obj100 = levelgen:findObjectById(100)

稍后在以下行中将打印Lua指向该userdata(obj100而非实际数据)的引用数:

print(ltraverse.countreferences(obj100))

这将始终为1,因为您刚刚创建了该对象,并引用了一个对象。

最有可能收集引用/ Lua对象,你不会看到它。实际的userdata(指针)总是相同的,因为您正在请求相同的对象ID。因此,除非通过某些其他代码移动/重新分配关联数据,否则此值不得更改。

但最后,我会说这实际上取决于levelgen:findObjectById()返回的内容。如果你尝试以下几行会怎么样?

local temp
local obj100 = temp = levelgen:findObjectById(100)