lupa icon indicating copy to clipboard operation
lupa copied to clipboard

Memory leak

Open guidanoli opened this issue 4 years ago • 2 comments

A dependency cycle avoids both Lua references and Python references from being collected by their respective garbage collection systems.

How to reproduce

This example uses __gc on tables, which is a feature not present in Lua 5.1, but is only there to show how the Lua object is not collected.

from lupa import LuaRuntime
lua = LuaRuntime()
lua_f = lua.eval('function(t) setmetatable(t, {__gc = print}) end')

###########################
# Normal behaviour
t = lua.table()
lua_f(t)
t = None
lua.execute('collectgarbage()')
# prints "table: <address>"
###########################

############################
# Unexpected behaviour
t = lua.table()
lua_f(t)
d = { "table": t }
t["dict"] = d
d = None
t = None
lua.execute('collectgarbage()')
# prints nothing --> table is not collected
#############################

guidanoli avatar Feb 10 '21 19:02 guidanoli

Is this impacted by the refcouting changes in #171?

scoder avatar Apr 21 '21 12:04 scoder

Is this impacted by the refcouting changes in #171?

No, there is still a reference cycle. Basically, in the example I gave, d is holding "hostage" the reference to _LuaTable, which holds "hostage" the reference to the Lua table in the registry (altough Python can't track the reference identifier down). In Lua, the table is holding "hostage" the reference to the userdata that points to d.

dict ---> _LuaTable (Python)
^                 |
|                 V
userdata <--- table (Lua)

I am using the word "hostage" here figuratively to emphasize that it's the only reference left! The problem here is that while there is clearly for us a reference cycle, it is split between languages and they can't see the full picture.

guidanoli avatar Apr 21 '21 12:04 guidanoli