Greetings,
I noticed that servers with a long lifespan tended to have high untracked server memory, and I would like to know how to either free this memory or keep it from getting that high in the first place.
After some experimentation, I found that loading in player’s characters and then destroying them increases server memory.
Sample: 4000 unique user’s characters loaded in over the course of 10 minutes (400 requests per minute from the API). Once the 10 minutes are finished, all models are removed using :Destroy() or other methods.
Environment: Not in studio. Testing in studio did not give accurate memory readings in Play Solo or Local Server.
Results: During the 10 minutes, untracked memory remains relatively low (100-200). Once all models were destroyed, untracked memory shot up past 1700. Staying in the game several minutes after destroying the models did not decrease untracked memory.
I tried a few destroying solutions to see if they help:
- :Destroy()
- Parent = nil
- Depth first removal of descendants
- Debris:AddItem
- Removing Humanoid first and then the model
Here is the server script I used to achieve this:
Note: There is a dummy character model inside the script running. Its the standard R15 Dummy generated from the animator plugin.
task.wait(8)
local api_request_limit = 400 -- api request limit is 400 a minute, so this takes X minutes to load
local userload = api_request_limit * 10
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local function loadid(id) -- given userid, put character randomly in workspace
local dummy = script.Dummy
local success, errmsg = pcall(function()
local character:Instance = dummy:Clone()
local des = Players:GetHumanoidDescriptionFromUserId(id)
character.Name = ""
character.PrimaryPart:PivotTo(CFrame.new(math.random(-500, 500), 0, math.random(-500, 500))*CFrame.Angles(0,math.random()*math.pi*2,0))
character.Parent = workspace
character.Humanoid:ApplyDescription(des)
end)
if not success then warn(errmsg) end
end
local function recursive(obj) -- NOT IN USE -- a method to see if this makes it clear memory easier --
for _,v in pairs(obj:GetChildren()) do
recursive(v)
end
pcall(function()
obj.Parent = nil
--obj:Destroy()
--Debris:AddItem(obj)
end)
end
do
local start = DateTime.now()
local n = userload/api_request_limit
for j = 1, n do
for i = 1, api_request_limit do
loadid(3652405999 + (j-1)*api_request_limit + i)
task.wait()
end
print(string.format("set %d complete", j))
task.wait((start.UnixTimestamp+60)-DateTime.now().UnixTimestamp) -- if we load <api_request_limit> users in under a minute, wait until the minute passed before continuing --
start = DateTime.now()
end
task.wait(5)
for _, v in pairs(workspace:GetChildren()) do
if v:IsA("Model") and not Players:GetPlayerFromCharacter(v) then
--local hum = v:FindFirstChild("Humanoid")
--if hum then hum:Destroy() end
--task.delay(.1,function()
-- recursive(v)
-- --v.Parent = nil
-- v:Destroy()
--end)
--v.Parent = nil
--Debris:AddItem(v)
--recursive(v)
v:Destroy()
end
end
end
I have looked through other devforum posts similar to this and still haven’t found a solid solution to avoid this memory increase. I kept the experiment as minimal as possible (no tables or connections) to try to find a solution, but any insight would be appreciated.
Devforum links:
Garbage collection
Weak tables
Caching parts for mining game
Connections causing memory leaks