Ada*_*dam 6 c lua garbage-collection lua-api
我试图通过使用C API将其存储在弱表中来为函数值创建GC终结器.
我开始在纯Lua 5.2中编写原型:
local function myfinalizer()
print 'Called finalizer'
end
function myfunc()
print 'Called myfunc'
end
local sentinels = setmetatable({}, { __mode='k' })
sentinels[myfunc] = setmetatable({}, { __gc=myfinalizer })
myfunc()
myfunc = nil
collectgarbage 'collect'
print 'Closing Lua'
Run Code Online (Sandbox Code Playgroud)
结果输出:
Called myfunc
Called finalizer
Closing Lua
Run Code Online (Sandbox Code Playgroud)
原型似乎按预期工作.以下是C版:
#include <stdlib.h>
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
static int my_finalizer(lua_State *L)
{
puts("Called finalizer");
return 0;
}
static int my_func(lua_State *L)
{
puts("Called myfunc");
return 0;
}
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// create sentinels table (weak keys) in registry
lua_newtable(L); // t
lua_newtable(L); // t mt
lua_pushstring(L, "k"); // t mt v
lua_setfield(L, -2, "__mode"); // t mt
lua_setmetatable(L, -2); // t
lua_setfield(L, LUA_REGISTRYINDEX, "sentinels"); //
// push global function and register as sentinel
lua_pushcfunction(L, my_func); // f
lua_getfield(L, LUA_REGISTRYINDEX, "sentinels"); // f t
lua_pushvalue(L, 1); // f t k
lua_newuserdata(L, 0); // f t k v
lua_newtable(L); // f t k v mt
lua_pushcfunction(L, my_finalizer); // f t k v mt v
lua_setfield(L, -2, "__gc"); // f t k v mt
lua_setmetatable(L, -2); // f t k v
lua_settable(L, -3); // f t
lua_pop(L, 1); // f
lua_setglobal(L, "myfunc"); //
// execute test script and exit
if (luaL_dostring(L, "myfunc(); myfunc=nil; collectgarbage'collect'")) {
printf("Error: %s\n", lua_tostring(L, -1));
}
lua_gc(L, LUA_GCCOLLECT, 0); // suggestion: two full gc cycles
fflush(stdout); // suggestion: immediate flush
puts("Closing Lua");
lua_close(L);
fflush(stdout);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
编译使用:
$ gcc -std=c99 -Wall -Werror -pedantic -O2 -o main main.c -ldl -llua52 -lm
Run Code Online (Sandbox Code Playgroud)
结果输出:
Called myfunc
Closing Lua
Called finalizer
Run Code Online (Sandbox Code Playgroud)
C版本有一些细微差别:
sentinels我存储在注册表中的本地表.__gcmetamethod的sentinel值表.我很困惑为什么在C版本中myfunc终结器在运行完整的收集周期后不会执行.我究竟做错了什么?
正如Lua手册所述:
仅从弱表中删除具有显式构造的对象.值(例如数字和轻C函数)不受垃圾收集的影响,因此不会从弱表中删除(除非收集其关联值).
你my_func的推送没有任何upvalues,因此它是一个轻量级C函数,并且在垃圾收集期间不会从弱表中删除,因此在关闭Lua状态之前,关联的userdata不会变为垃圾.如果您使用Lua函数而不是my_func,或者如果您my_func使用upvalues(并且如果您修复了lua_gc调用中参数的顺序!),那么您的代码应该可以工作.
总而言之,不会从弱表中删除以下值类型(假设它们的相关键/值也未被删除):
因此,你的程序应该可以正常使用Lua 5.1,因为没有简单的C函数(你仍然需要修复lua_gc调用).