Is there a way to actually know if something got garbage collected?
Example:
local p = Instance.new("Part")
local connection = p.Changed:Connect(function(property: string)
print(property)
end)
task.wait(1)
p:Destroy()
Would connection and p get garbage collected here? There is no easy way to check from what I can tell, since printing either of them would still work since it would need to keep a reference to the variable.
Printing gcinfo() isnt all that useful either since we dont know if the count increases because of this script, or if its just doing anything else in the background.
connection:Disconnect() --to remove the connection
connection = nil --to remove the reference
In your example, this would cause a memory leak as a reference to p is maintained in the connection, and the connection itself still has a reference in the code.
Destroy() doesn’t find all the possible references to a part, it simply parents it to nil and locks the property. It might appear absent in the workspace, but if other parts of code reference it then the GarbageCollector won’t actually collect it.
TBH I’m not sure how to definitively check a specific reference has been GC’d, other than to ensure all connections are disconnected and you set references to nil.
The reason why I made my own post in the first place is because I have something like this to handle character deaths and respawns:
local deathListeners = {}
local events = {}
type DeathListener = {
Died: RBXScriptSignal,
Respawned: RBXScriptSignal,
}
function connectDeath(player: Player, character: Model): ()
character:WaitForChild("Humanoid").Died:Once(function()
events[player].DiedEvent:Fire()
player.CharacterAdded:Wait()
events[player].RespawnEvent:Fire()
end)
end
function deathListeners.new(player: Player): DeathListener
if not events[player] then -- create new events
local diedEvent = Instance.new("BindableEvent")
local respawnEvent = Instance.new("BindableEvent")
if player.Character then -- handle existing character
connectDeath(player, player.Character)
end
player.CharacterAdded:Connect(function(character: Model) -- new character added
connectDeath(player, character)
end)
player.AncestryChanged:Once(function() -- player left the game
diedEvent:Destroy()
respawnEvent:Destroy()
events[player] = nil
end)
events[player] = {
DiedEvent = diedEvent,
RespawnEvent = respawnEvent,
}
end
local event = events[player]
return {
Died = event.DiedEvent.Event,
Respawned = event.RespawnEvent.Event,
}
end
return deathListeners
…and
-- in other server script
local deathListener = deathListeners.new(player)
deathListener.Respawned:Connect(function()
-- do whatever
end)
Wouldnt the script above cause a memory leak? I am destroying the events in the module, but they probably wouldnt get garbage collected since the server script has a reference to them, right?
Put deathListener.Respawned:Disconnect() inside the deathListener.Respawned:Connect() event.
Edit: I just realized the line where deathListener.Respawned:Connect() is at didn’t returned as a connection, make sure to make it as a variable and do respawnedConnection:Disconnnect() instead.
I misread the bottom part of your problem, so basically,
-- in other server script
local deathListener = deathListeners.new(player)
deathListener.Respawned:Connect(function()
-- do whatever
end)
No it wouldn’t cause any memory leak since you’re destroying both events and unindexing events[player]. If you’re like me I would’ve also put table.clear(events[player] too because I’m paranoid.
To know whether something was garbage collected, you can use a WeakReference. WeakReferences reference an object but don’t prevent it from being garbage collected. In Lua, you can create WeakReferenced tables like so:
local tbl = {}
setmetatable(tbl, {__mode = "v"})
An example:
local function tprint(tbl)
for k, v in pairs(tbl) do
print(tostring(k).." "..tostring(v))
end
end
local tbl = {"a", 2, 3.5, {}}
tprint(tbl)
print()
setmetatable(tbl, {__mode = "v"})
collectgarbage()
tprint(tbl)
Output:
1 a
2 2
3 3.5
4 table: 0x55c4e208bfd0
1 a
2 2
3 3.5
The reference type (the table at index 4) was garbage collected.
So, if you want to know whether connection was garbage collected: