Memory leak requiring modules?

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:
image

What am I doing wrong?

Edits: Clarification

I have a similiar problem when for example I create let’s say 10 000 parts and then destroy them the server memory doesn’t drop.

3 Likes

Roblox is quite buggy at the moment maybe its because of this.

That’s not the cause, becuase our problem was occuring in the past.

6 Likes