Experimenting with Untracked Memory and tables

Hello, I am currently experimenting with memory leaks. The objective of the experiment is to test how to properly dispose of dictionaries and tables without having Untracked Memory blow up. The experiment is a dictionary with tables whose values are random numbers, to simulate large amounts of data inside a dictionary, as well as to make changes in memory more visible. The experiment was run on a live server, not Studio. My question is how do you get rid of untracked memory, and if you cant, how do you remove tables without it going to untracked memory? Below is the results of my experiment

wait(10)
local S = game:GetService("Stats"):GetTotalMemoryUsageMb()
local Dictionary = {}
print("filling dictionary")
for i=1, 1500000 do
	Dictionary[tostring(i)] = {math.random(),math.random(),math.random(),math.random(),math.random()}
end
local F = game:GetService("Stats"):GetTotalMemoryUsageMb()
wait(1)
print("yeeting dictionary")
Dictionary = nil
print("Start ".. S)
print("Dict Fill " .. F)
print("End ".. game:GetService("Stats"):GetTotalMemoryUsageMb())
print("Setting to false")
wait(1)
Dictionary = false
print("End ".. game:GetService("Stats"):GetTotalMemoryUsageMb())
wait(600)
print("First 10 minutes is over.")
print("End ".. game:GetService("Stats"):GetTotalMemoryUsageMb())
script:Destroy()

image


End of first 10 minutes

image


After the last 10 minutes, change was seen



I decide to wait 10 more minutes to see if the untracked memory goes away, but there was no change.

1 Like

Solved. Solution was the following,

wait(10)
do
	local Dictionary = {}
	print("filling dictionary")
	for i=1, 1500000 do
		Dictionary[tostring(i)] = {math.random(),math.random(),math.random(),math.random(),math.random()}
	end
	setmetatable(Dictionary,{__mode = "kv"}) -- Sets the entire table as a weak table, allowing garbage collection of the table to be possible
end
print("done")

Thanks to this post for the information I needed, setmetatable by itself didn’t work, I waited 10 minutes to be sure and it did not. Wrapping it in a do end made the table get GCed much faster

Yep! That would be because you are still holding a reference somehow.
If you think about the entire script like its in a do end block, you can sort of see why that might be the case.

The reason the metatable isn’t working is because the values are numeric, meaning weak references don’t matter, so, setting the metatable in that case does nothing.

Garbage collection takes a while to happen sometimes, at most about 20 seconds from my testing, its not instant at all, so, generally you just want to make sure your table can be GCed.

do end blocks are a good way to be perfectly sure you’re not going to run into issues, because it isolates stuff.

Here’s an example of how you can use a do end block to ensure stuff can GC properly:

local someValueToExport
do
	local function someHelperFunction(...)
		-- Stuff
	end
	local someTableOfStuff = {...}
	
	someValueToExport = someHelperFunction(someTableOfStuff)
end

As soon as the do end block ends, the locals in it are freed and eventually will GC.

It really mostly comes down to the engine knowing when you aren’t using values. In the case of numbers and strings, I think the engine assumes you’re using them for whatever block they’re a part of.

By the way, I’m glad my post helped :smile:

1 Like

Ahh so that’s why it didn’t work without a do end, well gotta give you a big thanks for clearing these things up its a very big help :smile: