I won’t post the code unless necessary - approximately 700+ lines to read through - but I’m currently testing a localscript chunk by chunk to isolate a source of memory leaks. I have a table filled with functions and I manually set that table to nil whenever my character dies (the hume.Died connection should be disconnected whenever my character is destroyed, I assume) and yet the table and its functions linger in memory long after my character respawns. Does setting the variable holding the table to ‘nil’ not properly allow the table to be garbage-collected? The reference to the table isn’t held anywhere else.
You may have strong references in the table which are causing your leak and preventing the table from being garbage collected. What is your table comprised of? Furthermore, are you absolutely sure that you hold no references to the table itself?
I’m almost positive, yeah.
The table, as mentioned, is simply a dictionary of functions stored under a key - attacks that each class uses.
actions.Warrior = {
Normal = function()
local ind = atkIndex
local targets = {}
local index = {anims.slashA, anims.slashB, anims.slashC}
local size = {v3(4, 2, 5), v3(6, 2, 4), v3(3, 2, 7)}
local anim = index[ind]
local con = nil
con = anim:GetMarkerReachedSignal("Hit"):connect(function()
local pos = hrp.CFrame + hrp.CFrame.lookVector * 3
if ind >= #size then pos = pos + pos.lookVector * 1 end
effect("sound", {id = 1112042117, p = 1.5, pos = hrp}, common)
for _,targ in pairs(hitbox(pos, size[ind])) do
targets[#targets+1] = targ
end
con:Disconnect()
send:FireServer("Normal", {cf = pos, list = targets, size = size[ind], ind = ind})
end)
if atkIndex + 1 > #index then atkIndex = 1
else atkIndex = atkIndex + 1
end
anim:Play()
anim.Stopped:Wait()
con:Disconnect()
end,
UNormal = function()
local ind = atkIndex
local targets = {}
local index = {anims.spearA, anims.spearB, anims.spearC}
local size = {v3(4, 4, 6), v3(7, 2, 5), v3(4, 2, 8)}
local anim = index[ind]
local con = nil
con = anim:GetMarkerReachedSignal("Hit"):connect(function()
local pos = hrp.CFrame + hrp.CFrame.lookVector * 4
if ind >= #size then pos = pos + pos.lookVector * 1 end
effect("sound", {id = 1112042117, p = 1, pos = hrp}, common)
for _,targ in pairs(hitbox(pos, size[ind])) do
targets[#targets+1] = targ
end
con:Disconnect()
send:FireServer("Normal", {cf = pos, list = targets, size = size[ind], ind = ind})
end)
if atkIndex + 1 > #index then atkIndex = 1
else atkIndex = atkIndex + 1
end
anim:Play()
anim.Stopped:Wait()
con:Disconnect()
end,
Charged = function()
local size = v3(10, 2, 10)
local anim = anims.WChargeA
local spin = anims.WSpin
local ct = 1.5; chargeID = rdm(1, 9999999)
local this = chargeID
local now = tick()
anim:Play(); delay(ct - .1, function()
if anim.IsPlaying and chargeID == this then
anim:AdjustSpeed(0)
end
end)
effect("chargecircle", {id = chargeID, part = hrp, ct = ct, rad = 12, col = rgb(255, 255, 0)}, common)
while UIS:IsKeyDown(kc.E) do swait() end
local perc = clamp((tick()-now) / ct, 0.1, 1)
perc = ceil(perc * 100)
anim:Stop(); spin:Play()
effect("sound", {id = 12222208, pos = hrp}, common)
effect("sound", {id = 220834000, p = .8, pos = hrp}, common)
effect("endloop", {id = chargeID}, common)
for i = 1, 3 do local pos = hrp.CFrame; local targets = {}
for _,targ in pairs(hitbox(pos, size)) do
targets[#targets+1] = targ
end
send:FireServer("Charged", {cf = pos, list = targets, size = size, perc = perc})
wait(.1)
end
spin.Stopped:Wait()
end,
UCharged = function()
local hitdb = {}
local size = v3(3, 3, 8)
local anim = anims.WChargeB
local lunge = anims.WLunge
local ct = 1.5; chargeID = rdm(1, 9999999)
local this = chargeID
local now = tick()
anim:Play(); delay(ct - .1, function()
if anim.IsPlaying and chargeID == this then
end
end)
effect("chargecircle", {id = chargeID, part = hrp, ct = ct, rad = 10, col = rgb(255, 255, 0)}, common)
while UIS:IsKeyDown(kc.E) do swait() end
local perc = clamp((tick()-now) / ct, 0.1, 1)
perc = ceil(perc * 100)
anim:Stop(); lunge:Play(); hume.AutoRotate = false
effect("sound", {id = 12222208, pos = hrp}, common)
effect("endloop", {id = chargeID}, common)
local bv = i_n("BodyVelocity", hrp)
bv.MaxForce = v3(5*10^4, 0, 5*10^4)
bv.Velocity = hrp.CFrame.lookVector * (30 + (90 * perc/100))
game:GetService("Debris"):AddItem(bv, .3 + (.1 * perc/100))
for i = 1, floor(5 + (2 * perc/100)) do local targets = {}
local pos = hrp.CFrame + hrp.CFrame.lookVector * 4
for _,targ in pairs(hitbox(pos, size)) do
if not hitdb[targ] then hitdb[targ] = true
targets[#targets+1] = targ
end
end
send:FireServer("Charged", {cf = pos, list = targets, size = size, perc = perc})
wait(.06)
end
lunge:Stop()
hume.AutoRotate = true
end,
Block = function()
send:FireServer("Block")
while UIS:IsKeyDown(kc.Q) do
local state = hume:GetState()
if state == hst.Jumping or state == hst.Freefall then break
else swait()
end
end
send:FireServer("NoBlock")
end
}
Warrior is just one of the five classes - I’ll post the rest as requested.
There shouldn’t be any strong references in the functions - what I’ve learned from scouring the forums and doing my own research is that (apparently) variables that are localized to a scope no longer hold reference once that scope ends I.E. the function finishes executing.
This is the connection that clears the ‘actions’ table. It also breaks all external connections, and testing has shown that I’m not failing to break them - if I run the code without any entries in the ‘action’ table by just commenting them all out, I experience no leaks.
hume.Died:Connect(function()
for _,con in pairs(cons) do con:Disconnect() end
cons = nil; anims = nil; actions = nil
ping.OnClientInvoke = nil
end)
I know nothing about garbage collection in Roblox, but would recursively nullifying every value in the table before nullifying the table itself work?
Something like:
function clearTable(list)
for k, v in pairs(list) do
if (type(v) == "table") then
clearTable(v)
end
list[k] = nil
end
end
Can you elaborate on this? I don’t think a table can self reference itself once set to nil. I understand any complications that may arise if the table is a metatable but otherwise I don’t understand what this means, mind explaining?