2

I am creating userdata on Lua 5.3 and setting its uservalue (a table value). When I use collectgarbage() the uservalue is collected, however the userdata is not.

Why is the life cycle of userdata and uservalue different? How can I make the uservalue not be collected?

My code:

setpeer is a function to set uservalue(always is a lua table), getpeer is a function to get uservalue

LUA_API int setpeer(lua_State* L) {
/* stack: userdata, table */
if (!lua_isuserdata(L, -2)) {
    lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected.");
    lua_error(L);
};

if (lua_isnil(L, -1)) {

    lua_pop(L, 1);
    lua_pushvalue(L, XLUA_NOPEER);
};
lua_setuservalue(L, -2);
return 0;};

LUA_API int getpeer(lua_State* L) {

/* stack: userdata */
if (!lua_isuserdata(L, -1)) {
print_str(L, "gy in getpeer is userdata");
    lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected.");
    lua_error(L);
};

print_str(L, "gy in Getpeer, it is a userdata!");
lua_getuservalue(L, -1);
if (lua_rawequal(L, -1, XLUA_NOPEER)) {
    lua_pop(L, 1);
    lua_pushnil(L);
};
return 1;};

use setpeer in lua file, t is a c# object(userdata), and index is a lua table(like a class)

local setmetatableindex_
setmetatableindex_ = function(t, index)
if type(t) == "userdata" then
    local peer = xlua.getpeer(t)
    if not peer then
        peer = {}
        xlua.setpeer(t, peer)
    end
    --local mt = getmetatable(t)
    --if not mt then mt = {} end
    --if not mt.__index then
    --    mt.__index = peer
    --    setmetatable(t, mt)
    --end
    setmetatableindex_(peer, index)
else
    local mt = getmetatable(t)
    if not mt then mt = {} end
    if not mt.__index then
        mt.__index = index
        setmetatable(t, mt)
    elseif mt.__index ~= index then
        setmetatableindex_(mt, index)
    end
end
end

setmetatableindex = setmetatableindex_

then, I use this userdata, item is a userdata(c# object), update is a funtion in lua table. when I do collectgarbage(), update will be nil and getpeer return nil too, so I think uservalue has been gc-ed.(if not collectgarbage(), won't)

    item:update(dataArr[index+1])
renyson
  • 21
  • 2
  • 1
    Maybe your `uservalue` is referenced several times in your program. I think that when the garbage collector do his work, he will deallocate the `userdata` but not the `uservalue` because it is still needed by other software components. – Robert Nov 02 '21 at 06:36
  • 1
    Can you post your code to let us reproduce the bug (uservalue is indeed collected)? – Egor Skriptunoff Nov 02 '21 at 07:41
  • I post my code, could you please help to check, thanks~ – renyson Nov 02 '21 at 08:16
  • A mistake unrelated to your problem: you should write `setmetatableindex_(mt.__index, index)` instead of `setmetatableindex_(mt, index)` – Egor Skriptunoff Nov 02 '21 at 09:26
  • Your code is still not full to reproduce the bug. Can you write a small separate program? – Egor Skriptunoff Nov 02 '21 at 09:27

0 Answers0