Memory leak problem solved

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

hi laura,

thanks for sharing your thoughts on the subject.

im not expert in this but my thoughts and collected knowledge, which I hope to be accurate, is as follows:

your main issue was scope of lua code, as you discovered. it can be a pain, especially depending on which type of programmer you are.

i know people who are fast coders, often using code snippets they find on the web. they get fast results but often end up debugging alot, including scope issues. then there are those that at the other end of the scale (where i am) that refuse code snippets for anything but studying and learning. its slow and nerdy but I seldom get scope issues and debugging is never a big issue. I suspect you are a similar type. then of course there are this in between  :wink:

so, regarding display objects listeners, to my knowlege, anything connected to them like listeneres, tag etc is removed when the object is removed. this is also valid if the object is child of a display group and you remove the display group.

in general i try to nil variables that contain substance, like objects, large arrays and tables, file handling and such, but in general, there is no need to nil locally declared variable inside a function. they only exist while the program run inside the function.

putting variables in an array (and display objects for that matter) is never a bad idea since there is a lua limit that sometimes trigger the message “max 60 upvalues in function”, especially variables that are scoped for the entire lua script. this is not a must though since splitting a script into several sub functions grants 60 possible upvalues per function. i never get this issue anymore, unless I am missing an “end” somewhere in the code.

i dont know about requiring/unrequiring modules as i’ve never done unrequiring.

hope my houghts is of some help and have a great day out there!  :slight_smile:

in general i try to nil variables that contain substance, like objects, large arrays and tables, file handling and such, but in general, there is no need to nil locally declared variable inside a function. they only exist while the program run inside the function.

 

This was my plan as well but it got me thinking that in a large module you could end up with quite a large number of tiny local variables that would just never go away unless the module was un-referenced.  After the 2nd day of searching for my bug I started grasping at the tiniest of things.  I probably have 10 modules at 3k lines of code.  I bet there are 200 local variables in those things.  If they never get released they could add up.  Well that was my thought anyway.   I am not willing to go back and change all the local variables now that I am almost done.  But in the next thing I might just put them in _L from the beginning.  

One of my pet peeves with Lua is that variables default to being global instead of local and you have to type local a gazzilian times in your code.   Putting them all in _L would remove that annoyance.  Of course I could end up with weird scoping issues.  I will have to think this through some more. 

hi laura,

thanks for sharing your thoughts on the subject.

im not expert in this but my thoughts and collected knowledge, which I hope to be accurate, is as follows:

your main issue was scope of lua code, as you discovered. it can be a pain, especially depending on which type of programmer you are.

i know people who are fast coders, often using code snippets they find on the web. they get fast results but often end up debugging alot, including scope issues. then there are those that at the other end of the scale (where i am) that refuse code snippets for anything but studying and learning. its slow and nerdy but I seldom get scope issues and debugging is never a big issue. I suspect you are a similar type. then of course there are this in between  :wink:

so, regarding display objects listeners, to my knowlege, anything connected to them like listeneres, tag etc is removed when the object is removed. this is also valid if the object is child of a display group and you remove the display group.

in general i try to nil variables that contain substance, like objects, large arrays and tables, file handling and such, but in general, there is no need to nil locally declared variable inside a function. they only exist while the program run inside the function.

putting variables in an array (and display objects for that matter) is never a bad idea since there is a lua limit that sometimes trigger the message “max 60 upvalues in function”, especially variables that are scoped for the entire lua script. this is not a must though since splitting a script into several sub functions grants 60 possible upvalues per function. i never get this issue anymore, unless I am missing an “end” somewhere in the code.

i dont know about requiring/unrequiring modules as i’ve never done unrequiring.

hope my houghts is of some help and have a great day out there!  :slight_smile:

in general i try to nil variables that contain substance, like objects, large arrays and tables, file handling and such, but in general, there is no need to nil locally declared variable inside a function. they only exist while the program run inside the function.

 

This was my plan as well but it got me thinking that in a large module you could end up with quite a large number of tiny local variables that would just never go away unless the module was un-referenced.  After the 2nd day of searching for my bug I started grasping at the tiniest of things.  I probably have 10 modules at 3k lines of code.  I bet there are 200 local variables in those things.  If they never get released they could add up.  Well that was my thought anyway.   I am not willing to go back and change all the local variables now that I am almost done.  But in the next thing I might just put them in _L from the beginning.  

One of my pet peeves with Lua is that variables default to being global instead of local and you have to type local a gazzilian times in your code.   Putting them all in _L would remove that annoyance.  Of course I could end up with weird scoping issues.  I will have to think this through some more.