为什么在这种Lua 5.1 __gc解决方法中将userdata对象添加到表中?

时间:2019-04-09 05:25:18

标签: lua garbage-collection

我正在寻找将垃圾收集添加到Lua 5.1中的表(对象)的解决方案。我发现可以使用newproxy()__gc来解决此问题:

Lua 5.1 workaround for __gc metamethod for tables https://github.com/katlogic/__gc

我不理解的是作者使用userdata作为表中的字段插入。

  

通过此包装器在其上设置了元表的所有对象都将被特殊键__gc_proxy(可以是任何字符串,用户可以通过__GC_PROXY全局定义)“污染”。如果要遍历表的字段(next(),pairs()...),则必须对它进行特殊处理。

  

使用建议的解决方案时,需要注意一件事-如果您通过pairs()遍历表,您将获得一个加法键。可以通过使用具有适当元方法的代理对象代替原始表来避免这种情况。

这是来自堆栈溢出线程的复制/粘贴示例:

function setmt__gc(t, mt)
  local prox = newproxy(true)
  getmetatable(prox).__gc = function() mt.__gc(t) end
  t[prox] = true
  return setmetatable(t, mt)
end
iscollected = false
function gctest(self)
  iscollected = true
  print("cleaning up:", self)
end

test = setmt__gc({}, {__gc = gctest})
collectgarbage()
assert(not iscollected)

for k, v in pairs(test) do
   print(tostring(k) .. " " .. tostring(v))
end

输出为:

userdata: 0003BEB0 true
cleaning up:    table: 00039D58

但是此清理是从脚本结尾而不是在collectgarbage()的调用中进行的。

这可以通过以循环结尾的稍微修改的版本来证明。输出应为“清理中”:

function setmt__gc(t, mt)
  local prox = newproxy(true)
  getmetatable(prox).__gc = function() mt.__gc(t) end
  t[prox] = true
  return setmetatable(t, mt)
end

function gctest(self)
   print("cleaning up:", self)
   io.flush()
end

test = setmt__gc({}, {__gc = gctest})
collectgarbage()

while (true) do
end

相反,通过删除有问题的t[prox] = true,该集合将按预期工作:

function setmt__gc(t, mt)
  local prox = newproxy(true)
  getmetatable(prox).__gc = function() mt.__gc(t) end
  t[prox] = true
  return setmetatable(t, mt)
end

function gctest(self)
   print("cleaning up")
   io.flush()
end

test = setmt__gc({}, {__gc = gctest})
collectgarbage()

while (true) do
end

输出:

cleaning up

0 个答案:

没有答案