-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reference management questions #462
Comments
The reference should be in the registry. IIRC there is only one reference called for k, v in pairs(debug.getregistry()) do
print(k,v)
end |
Looks like there is more than that. At the start, there is:
Requiring luv adds:
After the handle initialization, they are indeed in there:
Somewhere during loop execution (the timer callback is irrelevant), A and C are removed from the registry (I assume because they are closed). Only C is collected because the local reference still exists for A.
Looking at the code, I see that (after static int luv_close(lua_State* L) {
uv_handle_t* handle = luv_check_handle(L, 1);
if (uv_is_closing(handle)) {
luaL_error(L, "handle %p is already closing", handle);
}
if (!lua_isnoneornil(L, 2)) {
luv_check_callback(L, (luv_handle_t*)handle->data, LUV_CLOSED, 2);
}
uv_close(handle, luv_close_cb);
return 0;
} static void luv_close_cb(uv_handle_t* handle) {
lua_State* L;
luv_handle_t* data = (luv_handle_t*)handle->data;
if (!data) return;
L = data->ctx->L;
luv_call_callback(L, data, LUV_CLOSED, 0);
luv_unref_handle(L, data);
} static void luv_unref_handle(lua_State* L, luv_handle_t* data) {
luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[0]);
luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[1]);
} Is there a reason why the handle is not unreferenced in |
Things can happen between This whole thing is something I was trying to wrap my head around as well and didn't get very far. One conclusion I sort-of-came-to is that I don't think luv currently has the necessary separation between 'things that should outlive the Lua VM (cleaned up by libuv)' and 'things that should be cleaned up by Lua' (also related to #437). We have // Note: this allows the handle to outlive lua_close/gc?
// since only the pointer to the heap-allocated chunk
// is actually tracked by Lua
static void* luv_newuserdata(lua_State* L, size_t sz) {
void* handle = malloc(sz);
if (handle) {
*(void**)lua_newuserdata(L, sizeof(void*)) = handle;
}
return handle;
} but I think we should be thinking about this case more when allocating things. |
Okay so it's not just me going down this rabbit hole. I got the answer to my questions though: the userdata isn't collected because it's still in the registry. That at least explains the behavior, even if it is janky. I'll close this and have a look at #437. Thanks guys. |
I'm trying to wrap my head around how userdata references are managed in luv.
Test script:
Questions:
In the first GC pass, after handle initialization, what is keeping each userdata and handle alive? I would expect at least
C
to be collected here because it is both closed and unreferenced by Lua.In the timer's GC pass,
C
is finally collected, but what changed between the two GC runs to affect this behavior?What happens at exit so that the remaining handles are collected?
(I have considered that my debug code might be keeping references alive, but I see the results with a reduced test.)
The text was updated successfully, but these errors were encountered: