Перехватчик для события удаления стейта.
Если Lua-библиотека, написанная на С, взаимодействует с несколькими Lua стейтами, то может потребоваться узнать о том, что какой-то из Lua стейтов удаляется. Сделать это можно так: при регистрации библиотеки в Lua стейте создаем безымянную userdata переменную, и у нее устанавливаем метатаблицу с методом __gc
. Поскольку при удалении стейта у всех объектов вызываются финализаторы, то будет вызвана и эта функция безымянного объекта.
int onDestroyLuaState(lua_State* L) { // делаем что-то полезное return 0; } const luaL_Reg libname[] = { // common functions {"Func1", func1}, {"Func2", func2}, ... {0, 0}, }; extern "C" __declspec(dllexport) int luaopen_libname(lua_State* L) { lua_newuserdata(L, 0); // dummy for GC lua_createtable(L, 0, 1); // metatable lua_pushcfunction(L, onDestroyLuaState); lua_setfield(L, -2, "__gc"); lua_setmetatable(L, -2); luaL_register(L, luaModuleName, libname); return 1; }
Объект нужно сохранить иначе его удалит сборщик мусора. Например в реестре.
Объект все время находится на стеке Lua, поэтому сборщик мусора не помечает его как готовый к удалению.
Приведенный ниже тест подтверждает это. Функция onDestroyLuaState() вызывается только во время вызова lua_close():
…
lua_newuserdata(L, 0); // dummy for GC
lua_createtable(L, 0, 1); // metatable
lua_pushcfunction(L, onDestroyLuaState);
lua_setfield(L, -2, «__gc»);
lua_setmetatable(L, -2);
lua_gc(L, LUA_GCCOLLECT, 0);
lua_close(L);
…
Этот пример не верный.
В статье вы загружаете модуль.
require «libname»
Вызывает `luaopen_libname` который получает свой стек который очищается когда завершается вызов.
корректный тест:
…
local lib = require «libname»
collectgarbage»collect»
collectgarbage»collect»
…
Э… Я вообще то на С++ пример показывал.
lua_gc(L, LUA_GCCOLLECT, 0); делает тоже самое что и collectgarbage»collect».
Это не имеет значения
void test(){
lua_State *L = luaL_newstate();
lua_pushcfunction(L, luaopen_libname);
lua_pcall(L, 0, 0, 0);
// coll twice just in case
lua_gc(L, LUA_GCCOLLECT, 0);
lua_gc(L, LUA_GCCOLLECT, 0);
lua_close(L);
}
Что ни делай (я проверял!), до тех пор, пока userdata лежит на стеке, сборщик мусора ее не удалит. В коде, который я привел, с этой переменной ничего не делается. А если ее сознательно или случайно вытолкнуть из стека, то да, сборщик мусора ее удалит.