I recently spent 2 days banging my head against my terminal trying to track down a 200k per level memory leak which I found unacceptable. Since I figured it out I thought I would share just in case someone else might benefit.
To keep my code simple the main code just has 2 things running: 1 an enterframe gameloop and 1 endless timer. Everything in the game is driven from these loops. Of course, display objects have their own collision listeners and sprite listeners as well.
The main code is structured like this:
exitfunction: – this is the only way out of the level.
– it does many things but the most important for this conversation is this:
Runtime:removeEventListener(“enterFrame”, gameLoop)
end
in the middle somewhere is a gameloop function.
At startup I have an initfunction which has this: Runtime:addEventListener(“enterFrame”, gameLoop)
All pretty straight forward right. Well as it turns out the removeEventListnerer failed without sending any kind of warning because the gameloop function is phyically below the exitfunction in the lua module. The result was that the enterframe gameloop never ended, ever. I don’t know how this didn’t cause more problems than a simple memory leak. Since when I restart a new level a new gameloop also gets started that would then never end as well. I had a player play the game for 2 hours and by that time the game really slowed down.
Since, all display objects are deleted in the exit function my texture memory showed no leaking. However, memory for local variables just grew and grew because lua I guess thought I was still using it in the never ending gameloops.
I have noticed that most of the conversations about finding memory leaks is focused around making sure display objects are removed and set to nil and removing listeners. However, the doc never mentions anything about sprite listeners and local variable. So I am unsure how they work.
1. Are sprite listeners automatically deleted when a display object is removed? They appear to be function listeners and not table listeners so I thought function listeners had to removed manually.
2. Do you have to nil out all your local variables as well before they are garbage collected? In my code they stay around well beyond the scope of the function in which they are first used. If this is true, would a best practice be something like this:
local _L = { } – put all local variables here
exitfunction: _L = nil.
Would this then nil out all local variables without having to do each one individually?
Does un-requiring the module they were first used in get rid of them? For example:
local XXX = require(“xxxcode”) – this module when then have 1 million local variables.
in the end can we just do this: package.loaded(“xxxcode”) = nil
Would that get rid of the 1 million local variables in one command?
Things I ponder the day after Thanksgiving, L