Better Garbage Collection

I have a player[1] memory leak somewhere in my game, and I’m guessing it’s because of something similar to this

local t=setmetatable({},{__mode='k'})
t[{}]=true
t[next(t)]={next(t)}

while next(t)do
	wait()
	print'in'
end
print'GCED'--never printed

The current GC doesn’t do this, but isn’t it more correct to say an object should be garbage collected iff after disconnecting all the weak references, no strong reference is reachable from a resumable thread? Maybe this is super difficult to implement, but it would be really awesome


[1] To allow for weak instance references I use

this module
--[[
	WIT: Weak Instance Table
	
	Lets weak tables use instances as weak references
	https://devforum.roblox.com/t/weak-tables-dont-work-with-instances/86634
	
	It doesn't really know when it is destroyed/gced though bc that is impossible, instead it knows if Parent is nil :/
		
--]]

local refs={}
local function add(ins)
	refs[ins]=true
end
local function rem(ins)
	refs[ins]=nil
end
for _,ins in ipairs(game:GetDescendants())do
	pcall(add,ins)
end
game.DescendantAdded:connect(function(ins)
	pcall(add,ins)
end)
game.DescendantRemoving:connect(function(ins)
	pcall(rem,ins)
end)

return nil

If anyone wants to check if they have a player memory leak in their game, run this code in a server script in accurate play solo studio and destroy/kick/remove the player instance from the server side and see if the output ever decreases from 1 to 0

code
local t=setmetatable({},{__mode='k',})

game:GetService'Players'.PlayerAdded:Connect(function(plr)
    t[plr]=true
end)

game:GetService'Players'.ChildRemoved:Connect(function(plr)
	game:GetService'Debris':AddItem(plr,1)
end)
local refs={}
local function add(ins)
	refs[ins]=true
end
local function rem(ins)
	refs[ins]=nil
end
for _,ins in ipairs(game:GetDescendants())do
	pcall(add,ins)
end
game.DescendantAdded:connect(function(ins)
	pcall(add,ins)
end)
game.DescendantRemoving:connect(function(ins)
	pcall(rem,ins)
end)


while wait()do
	local n=0
	for k,v in next,t do n=n+1 end
	print(n)
end

Probably only games that use weak player references will have memory leaks, but I’m curious about this nonetheless

2 Likes

What is your first example trying to convey? Your table has weak keys, but not weak values. The table you insert into it won’t be collected because it’s also being used as a value, which is not set to be a weak reference.

3 Likes

I want Roblox to (add the option to) change the behavior from what it is currently to

Then my example would GC as desired

1 Like

Yes, it would make sense to GC after there are only weak references and no strong references are reachable. However, you are creating a strong reference when you do t[your_table] = {your_table}. If you want this to GC, then your values should be weak, which is kv mode.

2 Likes

It is enough to just do v mode because the array has no other references, so your argument cannot be correct. The strong reference comes from indexing the array, which requires accessing the weak reference. But if the weak reference is removed, then you cannot access the strong reference anymore, so if the GC followed the feature request logic, then your_table would be gced

This is solved by ephemeron tables in 5.2, but according the most recent Luau roadmap, it isn’t going to be implemented:

Lua feature Lua version Our stance Comments
ephemeron tables 5.2 nope This seems like an extra complicated feature in GC without a strong use case
4 Likes

Off topic, but how would you have verified the ephemeron table functionality working for the OP example?
I did this, but I’m wondering if there’s a better way:

local t=setmetatable({},{__mode='k'})
t[setmetatable({},{__gc=print})]=true
t[next(t)]={next(t)}
print'1'
while true do local x={} end
print'2'
local q=t
1 Like

I just took OP’s example, replaced wait() with collectgarbage("collect"), and ran it in with the Lua 5.3 executable. It also works in the live demo.

4 Likes

(I do not know any non-Luau Lua LOL). Well, hopefully ephemeron tables get reconsidered sometime

1 Like

An up-to-date version of the feature compatibility is available here fwiw Compatibility - Luau.

We can reevaluate this decision but this will not happen soon as we are [right now] doing a major overhaul of the garbage collector. When we’re done (which will take months), we can reassess extra GC features but right now we’re simplifying the problem by not considering anything new that’s related to GC.

9 Likes

I’ll probably stick with the memory leaks, when it becomes problematic (eg 10k player join-leaves? idk) I’ll just shutdown the server somehow… alternatively it would be cool if you could give us the option to phase out servers via script so I could phase out high memory servers

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.