Weak tables are not garbage collected before running out of memory
planned
SuzannaLinn Resident
local tab1, tab2 = {}, {}
local weak = setmetatable({}, { __mode = "kv" })
for i = 1, 5000 do tab1[i] = i end
weak[1] = tab1
print(ll.GetUsedMemory()) -- > 83706
tab1 = nil
print(ll.GetUsedMemory()) -- > 83706
for i = 1, 5000 do tab2[i] = i end
-- > Script run-time error not enough memory
sleeping doesn't work:
local tab1, tab2 = {}, {}
local weak = setmetatable({}, { __mode = "kv" })
for i = 1, 5000 do tab1[i] = i end
weak[1] = tab1
print(ll.GetUsedMemory()) -- > 83741
tab1 = nil
ll.Sleep(3)
print(ll.GetUsedMemory()) -- > 83741
for i = 1, 5000 do tab2[i] = i end
-- > Script run-time error not enough memory
we need to move to another event, this works:
local tab1, tab2 = {}, {}
local weak = setmetatable({}, { __mode = "kv" })
for i = 1, 5000 do tab1[i] = i end
weak[1] = tab1
print(ll.GetUsedMemory()) -- > 83845
tab1 = nil
LLTimers:once(0, function()
print(ll.GetUsedMemory()) -- > 2190
for i = 1, 5000 do tab2[i] = i end
print("ok")
end)
-- > ok
Log In
H
Harold Linden
marked this post as
planned
Thanks for the report!
We're still figuring out the best way to handle this one, it's actually one of the oldest untracked bugs on the slua repo ( https://github.com/secondlife/slua/issues/13 )! There's a similar issue with the "shrinkable" table mode that Luau supports (hence the manual
table.shrink()
)Since SLua has different runtime needs than a typical garbage collected application, weak tables currently aren't terribly useful to us. They rely heavily on the garbage collector finally getting around to looking at our table and noticing that it can get rid of a bunch of objects. Allowing people to manually invoke the global garbage collector is also not good, because that's an extremely operation for doing what you _actually_ care about, breaking weak references in this specific script.
As noted on that task, the fix probably involves writing a sort of "mini" garbage collector that can walk just the current script's objects to look for weak references it can break when needed.
SuzannaLinn Resident
Harold Linden Could
table.shrink()
also garbage collect a weak table?H
Harold Linden
SuzannaLinn Resident Not easily no. Clearing references that are logically dead is a fundamentally different operation than typical table shrinking, and requires knowing the live-ness of all entries in the weak table. You have to walk the entire user script object to determine that, which is wear the "mini GC" would come in, and it would end up making more sense to just do it for all weak tables in that particular script at once, since you have to scan everything anyway. Possibly
collectgarbage()
could be repurposed to do that on-demand.Plus, in the specific case of you wanting to shrink a table, you could just mark the table shrinkable and let the mini-GC shrink it for you.