Am I getting memory problems due to yielding function?

EDIT After doing more testing, player:LoadCharacterWithHumanoidDescription(HumanoidDescription) doesn’t seem to cause memory leaks, however this resets the character, thus resetting their position, and UI elements. So this isn’t a viable solution!

I’ve been having memory problems for the past days with my character editor. When you ApplyDescription() rapidly (50-100 times in a minute say) it starts to build up the LuaHeap in memory.

The hub says this

This is a yielding function. When called, it will pause the Lua thread that called the function until a result is ready to be returned, without interrupting other scripts.

Not sure if I’m understanding this wrong, but would this possibly be a cause?

Code looks like this

local function Update(player, category, item)
	local Character = player.Character
	if not Character then return end
		
	local HumanoidDescription = Character.Humanoid:GetAppliedDescription()
	
	UpdateHumanoidDescription(player, HumanoidDescription, category, item)

	Character.Humanoid:ApplyDescription(HumanoidDescription)
	
	HumanoidDescription = nil
end

UpdateCharacter.OnServerEvent:Connect(Update)

When I comment out the ApplyDescription it doesn’t cause these memory problems

local function Update(player, category, item)
	local Character = player.Character
	if not Character then return end
		
	local HumanoidDescription = Character.Humanoid:GetAppliedDescription()
	
	UpdateHumanoidDescription(player, HumanoidDescription, category, item)

	--Character.Humanoid:ApplyDescription(HumanoidDescription)
	
	HumanoidDescription = nil
end

UpdateCharacter.OnServerEvent:Connect(Update)

BUT I also noticed that commenting out my UpdateHumanoidDescription and keeping the ApplyDescription there also doesn’t cause memory problems

local function Update(player, category, item)
	local Character = player.Character
	if not Character then return end
		
	local HumanoidDescription = Character.Humanoid:GetAppliedDescription()
	
	--UpdateHumanoidDescription(player, HumanoidDescription, category, item)

	Character.Humanoid:ApplyDescription(HumanoidDescription)
	
	HumanoidDescription = nil
end

UpdateCharacter.OnServerEvent:Connect(Update)

So how can I debug this? I’ve tried to create a repro, but it won’t work. There has to be something about HumanoidDescriptions I’m missing. Is it how I’m editing the HumanoidDescription?

This occurs for all changes across the humanoiddescription (adding accessories, changing body color, face, clothing, etc.)

In case it’s necessary

local function UpdateHumanoidDescription(player, humanoidDescription, category, item)
	local PlayerData = player:FindFirstChild('PlayerData')
	if not PlayerData then return end
	
	local function AccessoryToPlayerData(id, accessoryName)
		local Item = id
			
		local NewValue = Converter.Convertr(Item)
		NewValue.Name = id
		
		NewValue.Parent = PlayerData.Character[accessoryName]
	end
		
	-- Set the PlayerData values
	if category then
		-- Updating character
		local Data = PlayerData.Character:FindFirstChild(category)
		if not Data then return end
		
		if Data:IsA('Folder') then
			-- Accessory
			if Data:FindFirstChild(item) then return end -- if they already have the item worn, return
			
			--if #Data:GetChildren() >= 5 then return end -- no more than 5 items per category
			
			-- EDIT Need to check for VIP, and see if item requires VIP
			
			local NewItem = item
						
			local NewValue = Converter.Convertr(NewItem)
			NewValue.Name = item
			
			NewValue.Parent = Data
		else
			-- Value
			for i, v in pairs(CustomiseData[category]) do
				-- EDIT Need to check for VIP, and see if item requires VIP
				
				local ID -- Whether its the ID (for Shirts, Pants, Faces, etc. or Name for Body Colors
				if category == 'Body Color' then
					ID = v.Name
				else
					ID = i
				end
				
				if item == ID then
					Data.Value = ID
					
					if category == 'Bundle' then
						local Details = AssetService:GetBundleDetailsAsync(ID)
					end
				end
			end
		end
	else
		-- Loading character
		if PlayerData.Character['Roleplay Name'].Value == '' then
			-- No previous data
			PlayerData.Character['Roleplay Name'].Value = player.Name
			
			PlayerData.Character.Face.Value = humanoidDescription.Face
			PlayerData.Character.Shirt.Value = humanoidDescription.Shirt
			PlayerData.Character.Pants.Value = humanoidDescription.Pants
			
			-- Set default accessories
			for _, id in ipairs(humanoidDescription.HatAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Hats')
				end
			end
						
			for _, id in ipairs(humanoidDescription.HairAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Hairs')
				end
			end
			
			for _, id in ipairs(humanoidDescription.FaceAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Face Accessories')
				end
			end
			
			for _, id in ipairs(humanoidDescription.NeckAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Neck Accessories')
				end
			end
						
			for _, id in ipairs(humanoidDescription.ShouldersAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Shoulders Accessories')
				end
			end
			
			for _, id in ipairs(humanoidDescription.FrontAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Front Accessories')
				end
			end
						
			for _, id in ipairs(humanoidDescription.BackAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Back Accessories')
				end
			end
			
			for _, id in ipairs(humanoidDescription.WaistAccessory:split(',')) do
				if id ~= '' then
					AccessoryToPlayerData(id, 'Waist Accessories')
				end
			end
		end
	end
	
	-- Set HumanoidDescriptions for accessories
	local HatAccessories = {}
	for _, v in pairs(PlayerData.Character.Hats:GetChildren()) do
		table.insert(HatAccessories, v.Name)
	end
	
	humanoidDescription.HatAccessory = table.concat(HatAccessories, ', ')

	local HairAccessories = {}
	for _, v in pairs(PlayerData.Character.Hairs:GetChildren()) do
		table.insert(HairAccessories, v.Name)
	end
	
	humanoidDescription.HairAccessory = table.concat(HairAccessories, ', ')
	
	local FaceAccessories = {}
	for _, v in pairs(PlayerData.Character['Face Accessories']:GetChildren()) do
		table.insert(FaceAccessories, v.Name)
	end
	
	humanoidDescription.FaceAccessory = table.concat(FaceAccessories, ', ')
	
	local NeckAccessories = {}
	for _, v in pairs(PlayerData.Character['Neck Accessories']:GetChildren()) do
		table.insert(NeckAccessories, v.Name)
	end
	
	humanoidDescription.NeckAccessory = table.concat(NeckAccessories, ', ')
	
	local ShouldersAccessories = {}
	for _, v in pairs(PlayerData.Character['Shoulders Accessories']:GetChildren()) do
		table.insert(ShouldersAccessories, v.Name)
	end
	
	humanoidDescription.ShouldersAccessory = table.concat(ShouldersAccessories, ', ')
	
	local FrontAccessories = {}
	for _, v in pairs(PlayerData.Character['Front Accessories']:GetChildren()) do
		table.insert(FrontAccessories, v.Name)
	end
	
	humanoidDescription.FrontAccessory = table.concat(FrontAccessories, ', ')
	
	local BackAccessories = {}
	for _, v in pairs(PlayerData.Character['Back Accessories']:GetChildren()) do
		table.insert(BackAccessories, v.Name)
	end
	
	humanoidDescription.BackAccessory = table.concat(BackAccessories, ', ')
	
	local WaistAccessories = {}
	for _, v in pairs(PlayerData.Character['Waist Accessories']:GetChildren()) do
		table.insert(WaistAccessories, v.Name)
	end
	
	humanoidDescription.WaistAccessory = table.concat(WaistAccessories, ', ')
	
	-- Body sizes (need to base sizes on age)
	local Size = AgeSizes[PlayerData.Character.Age.Value]
	
	humanoidDescription.DepthScale = Size
	humanoidDescription.HeadScale = Size
	humanoidDescription.HeightScale = Size
	humanoidDescription.WidthScale = Size

	humanoidDescription.BodyTypeScale = 0
	humanoidDescription.ProportionScale = 0
	
	-- Face/Shirt/Pants
	humanoidDescription.Face = PlayerData.Character.Face.Value
	humanoidDescription.Shirt = PlayerData.Character.Shirt.Value
	humanoidDescription.Pants = PlayerData.Character.Pants.Value
	
	-- BodyColor
	humanoidDescription.HeadColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	humanoidDescription.LeftArmColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	humanoidDescription.LeftLegColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	humanoidDescription.RightArmColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	humanoidDescription.RightLegColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	humanoidDescription.TorsoColor = BrickColor.new(PlayerData.Character['Body Color'].Value).Color
	
	return humanoidDescription
end
1 Like

Looking further again into this, if I do

player:LoadCharacterWithHumanoidDescription(HumanoidDescription)

Instead of ApplyDescription, then lag isn’t created. However, this is a problem as it resets both UI, plus my characters position.