Using :Destroy() on a Instance doesn't properly cleanup memory

I’m trying to figure out ways to reduce memory for objects that are no longer needed within’ a server.

But it seems the method itself to remove them is flawed.

I made a test by creating 100k instances and then deleting them while also removing any and all references to them in the script then deleting the script. The outcome always shows that the memory stabilizes 100mb-200mb above what the initial memory was.

Script:
local memory_leak = {}

print("Wait 5 before leak")

wait(5)

print("Memory Leak!")

for i = 1, 100000 do
  local Part = Instance.new("Part")
  Part.Anchored = true
  Part.Parent = workspace

  table.insert(memory_leak, Part)

  Part = nil
end

print("Wait 5 before cleanup!")

wait(5)

print("Cleanup!")

for i = 1, #memory_leak do
  memory_leak[i]:Destroy()
  memory_leak[i] = nil
end

memory_leak = nil
script:Destroy()

Now my question is, is there any possible way to manage the memory to actually release any and all references of the object to free up the memory in question. This is in a case where the environment is perfect with no references to the deleted object.

I have seen responses saying that they keep them in reference to be ‘reused’ but wouldn’t be it better to give us the service/functions to fully release it to free memory? I feel like this would be the next big thing to be able to do if possible.

The outcome I want to be able to do is have memory restore to it’s near perfect state after the memory leak stress test.

You note that the memory increased above what it should be. Are you testing this in studio or the game client?

Studio, again the memory increase was expected when I created the instances I expected the memory to decrease to it’s initial amount after cleaning up the instances.

Here are the numbers I got while ingame and not studio.

314MB - Initial before memory leak test.

697MB - Instances are flooded in.

376MB - Instances are cleaned and memory is reduced.

Studio usually never yields the consistent or accurate memory results. Try testing in the game client itself. For example, on one of my games studio would take up just over 1gb of memory, but in game it was only a few hundred megabytes.

For after your post was edited:
Memory can be something that you can’t really rely on. It’s worth noting that it’s not consistent and can take some time before the garbage collector gets to cleaning up everything. Also, are you checking the memory with collectgarbage("count")?

Looks like you’re right, now I’m doing the tests in game.

But it still seems to not clean up fully.

I’m doing this tests on a baseplate game with nothing except the script in question.

So far it seems after cleanup an extra 50mb is left behind.

I’m not using collectgarbage(“count”) i’m referencing total memory from the f9 menu.

  1. Try testing memory with collectgarbage("count")
  2. Wait a little while after the cleanup should’ve happened to give the garbage collector some time
  3. Check the microprofiler for activity information from the garbage collector (is it doing things?)
  4. I can’t stress this enough, memory is often never consistent - but it’s always with investigating

I did give cleanup a little while and it suddenly spiked from 370 to 464 out of nowhere.

So giving it time to garbage collect but just suddenly wants to increase??.

I’m not sure, I just want my games to be as memory efficient as possible to support all platforms.

I can’t advise you beyond this point much; I can’t find much technical documentation about the garbage collector. Something to note is that the garbage collector runs basically at random, as we can’t control when it does. Also, creating 100k instances is quite a lot and probably more than most games. I wouldn’t worry too much.

I would assume you’re right, if I hit a roadblock on memory then I’ll have to deal with it when it happens.

1 Like

Just to add on to this, garbage collection runs every frame. Check Roblox Task Scheduler on DevHub, I think that’s what it’s called.

When I say it runs at random, I was mostly citing this:

But yes, it does “run” every frame.