How do I tell if my game is leaking?

Are there any guides to determining if a Corona app is leaking memory? And how to fix it?

I’ve read every thread in the forums that I could find on this subject…

(…a sampling…)
http://developer.anscamobile.com/forum/2010/12/30/memory-leak-touch-listener
http://developer.anscamobile.com/forum/2010/12/27/leak-or-me-not-getting-it
http://developer.anscamobile.com/forum/2010/12/08/memory-leak-when-removing-and-adding-image-sequencely
http://developer.anscamobile.com/forum/2010/11/25/memory-leak-issue
http://developer.anscamobile.com/forum/2010/12/15/memory-leak-uilua
http://developer.anscamobile.com/forum/2010/11/03/detecting-memory-leak

…and while there’s a lot of advice thrown around, I feel a bit confused. For instance, I put a display in a corner of my game that shows collectgarbage(“count”) every 100 milliseconds, and that number goes up & down all the time. The more sprites I put on the game screen, the faster that number cycles.

So I have some information, but I have no idea how to INTERPRET that information. I’m also hoping for some specific guidelines so I can be confident that my app isn’t going to get crash reports when I release it. So far my beta testers haven’t reported any problems, but I’m really worried about this.

Thanks in advance!
[import]uid: 9659 topic_id: 5041 reply_id: 305041[/import]

Instead of counting how many times garbage is collected I think a better approach is just to display the amount of memory being used.

I used the FPS code in the Code Exchange.

If the number starts to rise uncontrollably you’ve got a leak. If it keeps getting bigger when you change scenes back and forth, you’ve got a leak… I think you get the point.

That’s really all I did for my game and seemed to work fine. [import]uid: 10835 topic_id: 5041 reply_id: 16559[/import]

Just FYI, collectgarbage(“count”) returns the total memory in use by Lua (in Kbytes) … not the number of times garbage has been collected.

I’ll take a look at the texture memory too, thanks, I forgot about that.
[import]uid: 9659 topic_id: 5041 reply_id: 16561[/import]

Aahh I didn’t know that. Good to know.

However texture memory is probably the most important metric to keep track of if you’re developing a game. [import]uid: 10835 topic_id: 5041 reply_id: 16562[/import]

Here’s an example of what’s happening in my game.

Again, at the top of my game screen I added a small collectgarbage(“count”) display that updates in real time. When my game starts, and the level is initialized, the counter looks like this, second by second:

227, 233, 241, 248, 256, 264, 272, … 481, 502, 514, 523

After 35 seconds or so, it looks like gc takes over and ticks it down (though not all the way down to 227):

466, 414, 344, 269

After 3-4 seconds of freefall, it starts creeping back up again:

269, 276, 291, …

It goes up and down like this in about a 35 second cycle. After the first cycle, the minimum cycle number displayed is usually about the same, it doesn’t seem to creep up.

I figure this is a “normal” garbage collection cycle.

As soon as I do anything to affect the game (i.e. put something new on screen), the cycle starts accelerating. Instead of a 35 second cycle, it’s about 15 seconds. And the low number isn’t as low as it was before.

As I do more and more in the game, the cycle accelerates more and more, until it’s going up & down every 2 seconds.

It definitely seems strange. I’ve tried to keep everything tied to local variables (no globals anywhere), but I’m just not sure about what does or doesn’t need to be nil’d when I’m done with it.

I’m used to C/C++ where you have to delete everything you allocate. I know there’s a lot more freedom in Lua, but how much?
[import]uid: 9659 topic_id: 5041 reply_id: 16563[/import]

If someone wants to give me specific advice, that’s great, but really I’m looking for more general information (e.g., from Ansca) on what to look for when examining the memory use of a Corona app, and some specific programming practices beyond the couple of tips they give here:

http://developer.anscamobile.com/content/performance-and-optimization

For instance, assuming I use all locals and no globals at all for my data, if I create a table (myTable) with a bunch of nested tables, and I set myTable=nil, does that garbage collect all the data in the nested tables within? Or do I need to do a deep loop through myTable and set everything in it to nil?

Or if I use the director.lua module (by Ricardo Rauber), what variables do I need to nil in the unloadMe() function?
[import]uid: 9659 topic_id: 5041 reply_id: 16564[/import]

Thanks J, that’s an excellent description!

So I can see that using the director module – http://developer.anscamobile.com/code/director-class-10 – is generally a very good idea. Each module or screen is structured like this, in its own file:

function new()  
 local theGroup = display.newGroup()  
  
 -- your code --  
  
 unloadMe = function()  
 -- unloading code for listeners & transitions --  
 end  
  
 return theGroup  
end  

As long as you use nothing but locals inside function new(), everything should go to gc once it’s done.

Also, I’ve been trying to move as many functions as possible into existence as local functions within a larger function. That way, your rule 3 comes into play more often.
[import]uid: 9659 topic_id: 5041 reply_id: 16577[/import]

Where memory management in Corona gets trickier is that Corona maintains references to some objects in the background. For example, if you create a display object and then nil out references to that object, the memory is not freed because Corona itself still has a reference to that object. doh, leak! You need to call removeSelf to tell Corona to de-reference the object before you de-reference it in Lua.

That shouldn’t apply to any display objects you put in a group, right? I hope that the group deletes the objects it “owns”.
[import]uid: 9659 topic_id: 5041 reply_id: 16578[/import]

That’s a good question. Yes, removing a group recursively removes everything in the group. I’ve seen this explained in the documentation a few times; here’s one place, although this isn’t the clearest mention:
http://developer.anscamobile.com/reference/index/objectremoveself

Come to think of it, currently I’m using removeSelf on everything before removing the group they are in but I don’t have to. When I get home tonight I can get rid of a lot of removeSelf lines in my code.

I’m glad you found my earlier explanation helpful. I haven’t been programming in Lua long (only since I started using Corona, and you can see the date I registered) but it’s the same as how the garbage collector works in every other programming language. Incidentally, I want to add an additional caveat to situation 4 above:

4. Refer to the object in fields of another object, and then de-reference that other object. When the other object gets garbage collected, there will no longer be any references to the first object, so now the first object will be garbage collected.

There’s a really nasty bug that can happen called circular references. Basically, you can set one table to reference another, and then also set the second table to refer back to the first. Now if you lose all other references to these tables (eg. they were local variables) then neither will ever be garbage collected because there are references you can never get rid of. It would look like

function makeTables()  
 local t1 = {}  
 local t2 = {}  
 t1[1] = t2  
 t2[1] = t1  
end  
makeTables()  

Some languages have garbage collectors that check for circular references in order to clean them up, but many languages do not check for this problem and I don’t know about Lua. [import]uid: 12108 topic_id: 5041 reply_id: 16580[/import]

This is a great thread, and should be essential reading for everyone programming with Corona.

I want to subscribe to this thread and keep track of it, however there’s no way to do that without posting, hence this (mostly) pointless post. Just wanted to be up front about that :slight_smile: [import]uid: 49372 topic_id: 5041 reply_id: 34607[/import]

I want to subscribe to this thread and keep track of it, however there’s no way to do that without posting

Actually there is, but it’s not in the most obvious location. At the bottom right of the first post is a link for Subscribe. [import]uid: 12108 topic_id: 5041 reply_id: 34609[/import]

You’re right - never saw that there! And I looked for it over and over… thanks for the tip. [import]uid: 49372 topic_id: 5041 reply_id: 34618[/import]

I don’t know much about the director module, but for the nested tables question I can confirm that yes the garbage collector will get nested tables as well.

The thing about nil-ing variables is that you don’t literally need to set things to nil in order to garbage collect them; what the garbage collector actually needs is for an object not to have any references pointing to it. However setting variables to nil is a bulletproof method of ensuring that reference is gone, and so that is why you’ll see people suggesting nil-ing out your variables. I almost never do because that is just redundant code if you know what you’re doing.

There are actually multiple ways to lose a reference to an object (and thus allow it to be garbage collected):

  1. Set the variable referring to the object to nil. This is what many people around here suggest, and it is a good idea if you’re pretty new to programming, but if any of the other 3 situations apply then nil-ing the variable is redundant.

  2. Set the variable to another object. The original object is no longer being referenced, so it will be garbage collected. For example

local t = {} --create one table  
t = {} --create a new table, and now the first table is garbage  
  1. Refer to the object with a local variable inside of the function where it is created. The local variable goes away at the end of the function, which means there’s no more references to the object.

  2. Refer to the object in fields of another object, and then de-reference that other object. When the other object gets garbage collected, there will no longer be any references to the first object, so now the first object will be garbage collected.

The fourth situation is nested tables. (incidentally, I use the terms “object” and “table” pretty much interchangeably because, well, they are pretty much interchangeable concepts in lua.)

Where memory management in Corona gets trickier is that Corona maintains references to some objects in the background. For example, if you create a display object and then nil out references to that object, the memory is not freed because Corona itself still has a reference to that object. doh, leak! You need to call removeSelf to tell Corona to de-reference the object before you de-reference it in Lua.

I’m still trying to get a handle on how Corona handles memory for transitions and timers, but it seems like Corona de-references (or de-allocates, since Corona itself is written in C++ or Objective-C, not Lua) the transition object as soon as the transition completes. [import]uid: 12108 topic_id: 5041 reply_id: 16568[/import]

A quick anecdote and tip:

This is something I just solved in my current project. I have over 100 levels in the project, and have a simple level loader for now that allows me to move from level to level. Every level uses a different amount of memory, so I was having trouble seeing where my leak was, but I knew it was there because after going through a couple dozen levels they were getting noticeable slower to react to touches and the frame rate was dropping. I eventually made two complete cycles through the levels and charted the memory usage in each level on a graph and could see a clear trend line: the average memory usage was increasing slightly after every load (I used a spreadsheet to see the trend line, it wasn’t something I could really see in the raw numbers because every level varied so much in memory usage).

I realize there are any number of ways a memory leak can occur, but mine was such a little seeming mistake that was so tough for me to track down, I thought I’d share what I found:

I’d created a group that I used to handle the layer order of particular objects I wanted in the background. I rarely added objects to the group, and even tried inserting no objects into that group to see if that helped. Corona was dutifully creating a new display group every time I loaded a level, and since it wasn’t in the main display group, it wouldn’t be removed along with the rest of the scene when reloading, even though the group was assigned to a local variable within that scene. Putting that display group into the main group plugged the leak and removed the performance issue it was causing. The actual memory leak was really tiny, but it did quickly add up. I think I read every tip and every thread I could find about memory management twice over before it finally occurred to me what the problem was.
In short: Remember that even local display groups can create a memory leak if not properly disposed of when changing scenes. If you’re using the Corona Storyboard API, just make sure all display objects and display groups are inserted into the main group (self.view) every time and you won’t have the trouble I had! [import]uid: 14598 topic_id: 5041 reply_id: 87073[/import]