Need Help fixing a memory/lua heap leak in a no player collision script

I have a script where it sets players to not collide with each other, recently I made some changes I cant remember to it and now its staying in lua heap

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local playerCollisionGroupName = "Players"
PhysicsService:CreateCollisionGroup(playerCollisionGroupName)
PhysicsService:CollisionGroupSetCollidable(playerCollisionGroupName, playerCollisionGroupName, false)
--
--
--
local bluePlayerGroup = "BluePlayers"
PhysicsService:CreateCollisionGroup(bluePlayerGroup)
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, bluePlayerGroup, false)
local pinkPlayerGroup = "PinkPlayers"
PhysicsService:CreateCollisionGroup(pinkPlayerGroup)
PhysicsService:CollisionGroupSetCollidable(pinkPlayerGroup, pinkPlayerGroup, false)
--
local bluePartGroup = "BlueParts"
PhysicsService:CreateCollisionGroup(bluePartGroup)

local pinkPartGroup = "PinkParts"
PhysicsService:CreateCollisionGroup(pinkPartGroup)

--
--
--
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, pinkPlayerGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(pinkPlayerGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, pinkPartGroup, false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, bluePartGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, bluePlayerGroup, false) 
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, pinkPlayerGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, "Default", false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, "Default", false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, playerCollisionGroupName, false)
--
--
--

local previousCollisionGroups = {}

local function setCollisionGroup(object)
	--print("checking is its a part: "..object.Name)
	if object:IsA("BasePart") then
		previousCollisionGroups[object] = object.CollisionGroupId
		PhysicsService:SetPartCollisionGroup(object, playerCollisionGroupName)
		--warn(object.Name)
	end
end

local function setCollisionGroupRecursive(object) -- THIS IS LINE 52 WHERE THE LUA HEAP IS POINTING TOO
	setCollisionGroup(object)

	for _, child in ipairs(object:GetChildren()) do
		setCollisionGroupRecursive(child)
	end
end

local function resetCollisionGroup(object)
	local previousCollisionGroupId = previousCollisionGroups[object]
	if not previousCollisionGroupId then return end 

	local previousCollisionGroupName = PhysicsService:GetCollisionGroupName(previousCollisionGroupId)
	if not previousCollisionGroupName then return end

	PhysicsService:SetPartCollisionGroup(object, previousCollisionGroupName)
	previousCollisionGroups[object] = nil
end

local function onCharacterAdded(character)
	--warn("setting collision group for character")
	setCollisionGroupRecursive(character)

	local connectA = character.DescendantAdded:Connect(setCollisionGroup)
	local connectB = character.DescendantRemoving:Connect(resetCollisionGroup)
	
	character:GetPropertyChangedSignal("Parent"):Once(function()
		connectA:Disconnect()
		connectB:Disconnect()
	end)

end

Players.PlayerAdded:Connect(function(player)
	task.spawn(function()
		player.CharacterAdded:Wait()
		onCharacterAdded(player.Character)
		local connect = player.CharacterAdded:Connect(onCharacterAdded)
		player:GetPropertyChangedSignal("Parent"):Once(function()
			connect:Disconnect()
		end)
	end)
end)

Please note I do have multiple collision groups that players get set to within a game, also i made this script like 5 years ago so there may be some poor code practices

I hope I can get some help with this since im pretty bad at fixing memory issues like this

you know you can just do :GetDescendants() right?
i am 80% sure it’s because you never clear unneeded keys in previousCollisionGroups, so the memory just keeps being added onto that, but it is never cleaned up

(atleast i don’t see you calling resetCollisionGroup anywhere, maybe i’m blind)

Oops yea i forgot GetDescendants exists, I made this script so long ago I must of not learned that back then

resetCollisionGroup function gets called at local connectB = character.DescendantRemoving

okay, what kind of descendants get added and removed from the character?
also, why only run the GetPropertyChangedSignal('Parent') once? what kind of parent change is it

Hat Cosmetics get added to the characters (players can equip different in game hats)

GetPropertyChangedSignal(‘Parent’) is a way for me to check if that thing is getting removed (i tried other methods but it made more memory leaks)

you run that on the character, i’m not sure if you intended it that way

i don’t really have any other ideas

it is supposed to be run on the character, so that i can disconnect the functions character.DescendantAdded etc

The issue is you’re storing instance references into a Luau table (previousCollisionGroups), which won’t garbage collect due to wacky behaviors with Roblox’s reflection layer and C++ smart pointers.

You’ll have to manually remove the instance references from the Luau table for them to properly collect. To do that, just iterate over the character’s child instances on Player.CharacterRemvoing and set their values in the table to nil.

got it ill try seeing if that works, just gonna use a loop over the character with the resetCollisionGroup functoin

Just a word of caution: If somehow an instance you stored gets destroyed before you iterate over the character’s descendants, you won’t be able to remove it from the table and it’ll just stay there in memory.

You’ll probably have better luck storing all the objects in a ‘bucket’ associated with the character model and then just niling out the bucket when the character gets removed. That way, if a descendant of the character gets removed before the whole character is, it’ll still get removed from the table and get collected.

roblox studio is not letting me publish changes cause it went down I cant even check if the fixes I just did to this script works :sob:

Edit: I’m also going to try to see if I even need to save objects into a table cause i can’t actually see a reason why I need it

I ended up figuring out i didnt even need to store character objects in the first place, i just removed the table lol

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local playerCollisionGroupName = "Players"
PhysicsService:CreateCollisionGroup(playerCollisionGroupName)
PhysicsService:CollisionGroupSetCollidable(playerCollisionGroupName, playerCollisionGroupName, false)
--
--
--
local bluePlayerGroup = "BluePlayers"
PhysicsService:CreateCollisionGroup(bluePlayerGroup)
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, bluePlayerGroup, false)
local pinkPlayerGroup = "PinkPlayers"
PhysicsService:CreateCollisionGroup(pinkPlayerGroup)
PhysicsService:CollisionGroupSetCollidable(pinkPlayerGroup, pinkPlayerGroup, false)
--
local bluePartGroup = "BlueParts"
PhysicsService:CreateCollisionGroup(bluePartGroup)

local pinkPartGroup = "PinkParts"
PhysicsService:CreateCollisionGroup(pinkPartGroup)

--
--
--
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, pinkPlayerGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePlayerGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(pinkPlayerGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, pinkPartGroup, false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, bluePartGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, bluePlayerGroup, false) 
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, pinkPlayerGroup, false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, "Default", false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, "Default", false)
PhysicsService:CollisionGroupSetCollidable(bluePartGroup, playerCollisionGroupName, false)
PhysicsService:CollisionGroupSetCollidable(pinkPartGroup, playerCollisionGroupName, false)
--
--
--

--local previousCollisionGroups = {}

local function setCollisionGroup(object)
	--print("checking is its a part: "..object.Name)
	
	if object:IsA("BasePart") then
		--previousCollisionGroups[object] = object.CollisionGroupId
		PhysicsService:SetPartCollisionGroup(object, playerCollisionGroupName)
		
		
	end
end

local function setCollisionGroupCharacter(object)
	--warn("setting collision group for character")

	for _, child in ipairs(object:GetDescendants()) do
		--print(child.Name)
		setCollisionGroup(child)
	end
end
--[[
local function resetCollisionGroup(object)
	--warn(object.Name.." reseting")
	local previousCollisionGroupId = previousCollisionGroups[object]
	if not previousCollisionGroupId then return end 

	local previousCollisionGroupName = PhysicsService:GetCollisionGroupName(previousCollisionGroupId)
	if not previousCollisionGroupName then return end

	PhysicsService:SetPartCollisionGroup(object, previousCollisionGroupName)
	previousCollisionGroups[object] = nil
end
--]]
local function onCharacterAdded(character)
	--setCollisionGroupCharacter(character)

	local connectA = character.DescendantAdded:Connect(setCollisionGroup)
	if character:FindFirstChild("HumanoidRootPart") then
		setCollisionGroup(character.HumanoidRootPart)
		--warn("ahfiewhfksjd")
	end
	setCollisionGroupCharacter(character)
	--local connectB = character.DescendantRemoving:Connect(resetCollisionGroup)
	local connectC
--	warn(character.Parent)
	connectC = character:GetPropertyChangedSignal("Parent"):Connect(function()
		--connectA:Disconnect()
		if character.Parent == nil then
			--warn("HAHAHWRH")
			--warn(character.Parent)
			connectA:Disconnect()
			--connectB:Disconnect()
			--[[
			if character then
				for i,object in character:GetDescendants() do
					if object:IsA("BasePart") then
						resetCollisionGroup(object)
					end
				end
			end
			--]]
			connectC:Disconnect()
		end
	end)

end

Players.PlayerAdded:Connect(function(player)
	task.spawn(function()
		player.CharacterAdded:Wait()
		onCharacterAdded(player.Character)
		local connect = player.CharacterAdded:Connect(onCharacterAdded)
		player:GetPropertyChangedSignal("Parent"):Once(function()
			--warn(player.Name.." leaving we disconnecting no collide function")
			connect:Disconnect()
		end)
	end)
end)

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