How do I observe the memory system so I can manage it properly?

Docs always talk about removing stuff from memory. Generally this seems to involve using some special deletion function if it’s related to listeners/solar2dFuncs and setting any variables that point to it to nil.

I find this ambiguous though especially in relation to the scene system. And more so when I have a bunch of tables and references to things via those tables going on. It’s easy to lose track of what is pointing to what when you tack on globals outliving the scene. Is there a way to observe the memory system so I know I’m not missing setting something to nil?

Like with audio it says when you are done with track1 to run audio.dispose(track1) track1=nil. In the tutorial though it just has you call audio.dispose(track1) in scene:destroy(). Are all locals destroyed on scene destruction so it’s redundant and u don’t need to set track1=nil?

What is even the point of demanding I manually dispose of the audio after the scene is gone? If the audio is a global variable I can use it in other scenes after declaring it inside a scene, and audio.dispose doesn’t seem to work on it if it’s a global variable (worked in other scenes anyways). If it’s a local I can’t use it in other scenes and audio.dispose works on it (most sounds like shooting u wouldn’t dispose of until the scene is being deleted tho). So why wouldn’t all the audio just automatically get run through audio.dispose and killed from memory when the scene deletes? Why make me manually write them all out?

To bring that back to the OP (how do I observe the memory changes), I made a system to automate the task incase I have a thousand audio clips, in scene:destroy():

monitorMem = function()
     collectgarbage()
     print("MemUsage: " .. collectgarbage("count"))

     local textMem = system.getInfo("textureMemoryUsed") / 1000000
     print( "TexMem: " .. textMem )
end

function scene:destroy(event) local sceneGroup = self.view -- runs after composer.removeScene"test"
	print("we are in test.lua destroy")
	monitorMem()
	for i=1,#sfx_key do audio.dispose( sfx_store[ sfx_key[i] ] ) end --removes all audio generated in the scene
	monitorMem()
end

--the for loop disposing audio commented out:
-- MemUsage: 361.40234375
-- MemUsage: 361.2587890625

--the for loop disposing audio active:
-- MemUsage: 361.67578125
-- MemUsage: 361.5322265625

So everytime I run the game the numbers are the same, and as soon as I comment out the for loop they of course change but remain consistent once more. If the first numbers were the same, I could see a change, but they aren’t. So how am I supposed to tell the difference between disposing my audio and not? monitorMem() taken from Managing Memory : does it need to go back to the initial state ?

Even just writing out the normal audio system and loading then disposing a dozen tracks one by one, using audio.dispose() isn’t giving any indicator it did anything after its used (nor is the memory function) and u can still print the variable after and get userdata…audio.dipose doesn’t stop the audio from playing either, how would I know it even worked? (it’ll crash the game if u try to play the audio after its run through audio.dispose, thats the only method I can find to see its doing anything). And if it’s printing user data, how would I know it is deleted when it moves to the next scene? Even if it is doing something, doesn’t this still mean the tutorial is wrong and u do need to infact set it to nil after? How would I even confirm that the local varaible in a scene I deleted was set to nil or put in a state where its not taking up memory once I am in a new scene? Or do I even have to move to a new scene I can just sit in the deleted one potentially.

In Solar2D, you cannot monitor audio memory usage directly, that is separate from Lua memory usage and texture memory usage (provided by the API).

If you want to detect whether you have a memory leak on your app then the simplest approach would be to use Task Manager (Windows) or Activity Monitor (MacOS) and check its memory usage.

For audio files, if they are used in multiple scenes then no need dispose them and load them again on next scene.

For these type of objects, there’s a difference between the assigned Lua reference (variable) to the object and the object itself in memory, whether texture or audio data.

To understand how things work in the environment, you can create a texture or audio object by calling its API with or without a reference, and while both are valid, without a reference you won’t be able to manage the object, and each one needs to be disposed properly, thus using display.remove(reference) or audio.dispose(reference) respectively.
Simply setting the reference to nil doesn’t remove the object from memory, it only removes its reference.

-- creating objs with reference
local img = display.newImage(pathToTexture)
local sfx1 = audio.loadSound(pathToAudioFile)

-- later on...
img = nil -- reference set to nil but object still exists in memory
audio.dispose(sfx1) -- remove object from memory
sfx1 = nil -- set reference to nil, not necessary unless you’re checking this reference in another code block to see whether it’s nil.

-- creating objs without reference; though they are created you cannot manage them.
display.newImage(pathToTexture)
audio.loadSound(pathToAudioFile)