I have recently been debugging serious memory leaks in my game.
A server will start with roughly 500 MB memory on the server, and within 9 hours it went to 2000.
I have tried debugging through checking for differences with this simple loop:
while wait(1) do
local count = collectgarbage('count')
count = math.floor(count)
print(count, count - lCount)
lCount = count
for _,v in pairs(ps) do
v:LoadCharacter()
end
end
I have found that whenever a player respawns, the count jumps up by about 60 and doesn’t drop.
I have done the practices by making sure all connections are disconnected, players and other things are removed from tables when not needed, etc etc.
However something very strange I noticed is that when I commented out the code in my MeleeHandler that requires the configurations for that weapon, it only goes up 20 per respawn. I have tried everything and for some reason it still happens.
NewMeleeEvent.Event:Connect(function(Tool)
if cMelees[Tool] then return end
local nMelee = {}
nMelee.Equipped = false
nMelee.Tool = Tool
cMelees[Tool] = nMelee
local function GetTing(cL,sCharacter)
local x = cL
if x[1] == "Tool" then
return Tool:FindFirstChild(x[2])
elseif x[1] == "Char" and sCharacter then
return sCharacter:FindFirstChild(x[2])
end
end
local instance_config = ToolModules.Melees[Tool.Name]:Clone()
instance_config.Name = "Config"
instance_config.Parent = Tool
local config = require(instance_config)
--if game then return end
local Handle = GetTing(config["Handle"],nil)
local customModulesDir = Tool:FindFirstChild("Modules")
local animsDir = Tool:FindFirstChild("AnimsFolder")
local SoundsDir = Tool:FindFirstChild("Sounds")
local cST = ""
local gsNum = 0
local executeAnim = nil
local disconnected = false
local eCon
local customs = {}
local slashCodes = {}
local lCharacter
local function NewAnim(Humanoid,n)
if animsDir:FindFirstChild(n) then
return Humanoid:LoadAnimation(animsDir[n])
else
local a = Instance.new("Animation")
a.AnimationId = "rbxassetid://0"
game.Debris:AddItem(a,0)
return Humanoid:LoadAnimation(a)
end
end
local Values = Instance.new("Folder")
Values.Name = "Values"
Values.Parent = Tool
local Slashing1 = Instance.new("BoolValue")
Slashing1.Name = "Slashing1"
Slashing1.Parent = Values
local CustomFlinch = Instance.new("BoolValue")
CustomFlinch.Name = "CustomFlinch"
CustomFlinch.Parent = Values
local SlashDB = Instance.new("BoolValue")
CustomFlinch.Name = "SlashDB"
CustomFlinch.Parent = Values
local BlockValue = Instance.new("BoolValue")
BlockValue.Name = "Blocking"
BlockValue.Parent = Values
local ExecuteValue = Instance.new("BoolValue")
ExecuteValue.Name = "Executing"
ExecuteValue.Parent = Values
if config.Customs["Pickup"] then
local x = Instance.new("BoolValue")
x.Name = "Grabbing"
x.Parent = Values
customs.GrabValue = x
end
local cmEvent = Instance.new("RemoteEvent")
cmEvent.Name = "Event"
cmEvent.Parent = Tool
local eventCon = cmEvent.OnServerEvent:Connect(OnRemote)
local comboHitCount = 0
local lastSNum = 1
local lastHitChar
local con1,con2
local function DisconnectFunc()
if disconnected then return end
pcall(function()
disconnected = true
nMelee.UnequipFunc(true)
if Handle and Handle.Parent then
Handle.CanCollide = true
Handle.Massless = true
for _,v in pairs(Handle:GetJoints()) do
v:Destroy()
end
end
end)
if customModulesDir and customModulesDir:FindFirstChild("Disconnect") then
require(customModulesDir["Disconnect"])
end
instance_config:Destroy()
customs = nil
slashCodes = nil
lCharacter = nil
lastHitChar = nil
config = nil
con1:Disconnect()
con2:Disconnect()
nMelee = nil
cMelees[Tool] = nil
Tool:Destroy()
Tool = nil
eventCon:Disconnect()
eventCon = nil
cmEvent:Destroy()
cmEvent = nil
Values:Destroy()
Values = nil
return
end
con1 = Tool.Equipped:Connect(function() nMelee:EquipFunc() end)
con2 = Tool.Unequipped:Connect(function() nMelee:UnequipFunc() end)
local ansCON
ansCON = Tool.AncestryChanged:Connect(function(_,Parent)
if not Parent or (Parent.Name ~= "Backpack" and not Players:GetPlayerFromCharacter(Parent)) then
DisconnectFunc()
ansCON:Disconnect()
end
end)
------------------------------------------------------
Below this are just the functions, and by commenting out no difference was made. By commenting out
local config = require(instance_config)
, the collectgarbage count drops to 20 per respawn, but why does this never clean up??? A note is that this simply returns a table and does nothing else.
On an empty baseplate doing this in a script inside ServerScriptService:
local lCount = 0
while wait(1) do
local count = collectgarbage('count')
count = math.floor(count)
print(count, count - lCount)
lCount = count
local config = script.Bat:Clone()
config.Name = "Config"
config.Parent = workspace
local rConfig = require(config)
delay(0.1,function()
config:Destroy()
rConfig = nil
config = nil
end)
end
This is the result I get from above as expected:
What am I doing wrong?
Edits: Clarification