[Guide] Finding/Solving Memory Leaks

20 replies [Last post]
Danny
User offline. Last seen 2 years 35 weeks ago. Offline
Joined: 17 Aug 2011

When you have memory leaks in your app/game generally there are several common things at fault. These are listed below, you should always adhere to these practices:

1) Always ensure to remove all runtime and object listeners before/during changing scenes. If you don't you will have both memory leaks and odd bugs.

EG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local function imageFunction(event)
    return true
end
 
local function runTimeFunction(event)
    return true
end
 
 
local myImage = display.newImage("myImage.png")
myImage:addEventListener("touch", imageFunction)
Runtime:addEventListener("enterFrame", runTimeFunction)
 
--Get rid of them
myImage:removeEventListener("touch", imageFunction)
Runtime:removeEventListener("enterFrame", runTimeFunction)

2) Always cancel timers when changing scenes and always as a rule create a variable to store your timer so you can cancel it.

EG:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--Create a forward reference for the timer (also known as "predeclaring"
local myTimer
 
local function testFunction()
    print("Hello")
end
 
--Create the timer
myTimer = timer.performWithDelay(1000, testFunction)
 
--get rid of the timer
if myTimer ~= nil then
    timer.cancel(myTimer)
end
 
myTimer = nil

3) When removing images be sure also to nil out the reference to the image, if you don't do this the lua garbage collector won't class it as garbage and it will remain in memory.

EG:

1
2
3
4
5
local myImage = display.newImage("myImage.png")
 
--Get rid of it
display.remove(myImage)
myImage = nil

4) When removing audio, ensure to follow the following steps:

Stop Audio > Dispose of audio > Nil audio handle and sound file reference.

EG:

1
2
3
4
5
6
7
8
local myAudioFile = audio.loadSound("mySound.mp3")
local myAudioHandle = audio.play(myAudioFile)
 
--Get rid of it
audio.stop(myAudioHandle)
audio.dispose(myAudioFIle)
myAudioHandle = nil
myAudioFile = nil

5) Always cancel transitions when changing scenes and always as a rule create a variable to store your transition so you can cancel it.

EG:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--Create a forward reference for the transition (also known as "predeclaring"
local myTransition
 
local myImage = display.newImage("myImage.png")
myImage.alpha = 0
 
--Create the transition
myTransition = transition.to(myImage, {alpha = 1})
 
--get rid of the transition
if myTransition ~= nil then
    transition.cancel(myTransition)
end
 
myTransition = nil

6) When creating functions to create objects (text, images etc) always make sure you return the object, if you don't then you have no way of clearing its memory

EG:

1
2
3
4
5
local function createBox()
    local box = display.newImage("box.png")
    
    return box
end

7) When changing text, change the text object directly, don't keep creating new text objects.

EG:

1
2
3
4
5
6
7
8
9
10
11
local function createHighScore()
    local highScore = display.newText("high score: 0000", 100, 100, native.systemFont, 24)
    
    return highscore
end
 
--Create the highscore text object
local highScore = createHighScore()
 
--Update the score
highscore.text = "high score: 0100"

But wait, I haven't been doing this and my game is leaking memory between scene changes

Don't worry, it's not too late. Here is one way you can work out what part of your code is causing the leak.

1) Code commenting. Start piece by piece commenting out sections of your code. Do this piece by piece though, don't rush ahead. Comment out say the function that spawns your enemies, start your game change scenes and monitor your memory usage, if it goes down (even by a small bit) you know that in the commented part of your code that you are leaking a bit of memory in there.

2) Comb through all your code files looking for things I mentioned above. It may take time but if you put the effort in you will see results.

How do i print my memory usage?

1) If you are using storyboard and have storyboard.isDebug set to true you can use the following command:

storyboard.printMemUsage()

I would recommend placing this in your enterscene function.

2) If you are using director, scene manager or are using something you created yourself... you can use the following function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local function printMemUsage()          
        local memUsed = (collectGarbage("count")) / 1000
        local texUsed = system.getInfo( "textureMemoryUsed" ) / 1000000
        
        print("\n---------MEMORY USAGE INFORMATION---------")
    print("System Memory Used:", string.format("%.03f", memUsed), "Mb")
        print("Texture Memory Used:", string.format("%.03f", texUsed), "Mb")
    print("------------------------------------------\n")
     
    return true
end
 
--Call it at the beginning of your new scene or the first line under your .new() function
 
printMemUsage()

Iv'e done all this but I am still leaking memory?

It is nearly impossible to write 100% bug/memory leak free code, it comes hand in hand with the profession. The following are safe regions of memory leaks and are nothing to worry about:

1kb > 8kb

If you are leaking more than that then I would suggest trying the things I have mentioned to get it lower.

You may find that your memory usage climbs for a while then drops off to it's original usage again, this is the expected behavior and how the lua garbage collector works, it's memory removal is not always instant, you need to bear that in mind.

Ok I've tried everything and I am still leaking more memory than you said should be ok

If you have exhausted every option, tried all my techniques, asked on the forums (etc) and are 100% sure your code shouldn't be leaking but it is, you have one last alternative. You can avail of our premium support service and one of our trained members of staff will work with you on your code. You can find more info on this here: http://www.anscamobile.com/corona/support/

Replies

Naomi
User offline. Last seen 8 weeks 3 days ago. Offline
Joined: 6 Jun 2011

Thank you, Danny, for this post. It's super helpful.

By the way, you noted 1kb > 8kb is safe enough for memory leak. I'm wondering what you mean? Did you mean anywhere between 1kb and 8kb leakage should be tolerable?

Naomi

Danny
User offline. Last seen 2 years 35 weeks ago. Offline
Joined: 17 Aug 2011

Yes anywhere from 1kb>8kb is nothing to be concerned about. If you go nuts like I did on my personal project, you can get it lower. Currently my own game leaks 1kb of memory and gains that 1kb back after a few scene changes. So basically I am leaking 1kb every 3>4 scene changes.

Axie Studios
User offline. Last seen 5 years 50 weeks ago. Offline
Joined: 1 Feb 2012

I've read all over the forum that when you remove the object it's EventLstener also get's removed so is this not the case?

1
2
3
4
5
6
7
8
9
10
local button = newImage("button.png")
 
local function Do Something()
--doing stuff
end
 
button:addEventListener("touch", DoSomething)
 
button:removeSelf();
button = nil;

In an example like this do I still need to remove it manually? Typing this next piece?

1
button:removeEventListener("touch", DoSomething)

soccermanandrei
User offline. Last seen 6 years 1 week ago. Offline
Joined: 15 Jan 2012

Guys my multiscreen app doesn't seem to be leaking any memory between scenes (its under 2kb) but during gameplay the memory usage slowly crawls up to around 500 and only then gets collected by the garbage collector and this causes stutter on actual android devices. is this normal for lua memory to grow during gameplay? Note: I'm not spawning, adding event listeners or anything of that sort.

Even in this very simple code lua memory slowly rises...
http://codeviewer.org/view/code:27df

projects1
User offline. Last seen 4 years 15 weeks ago. Offline
Joined: 3 Jan 2012

Hi Danny very useful post , helps new guys like me .

i have one doubt, if i use a display object to insert all my display items. is

disp_group:removeSelf()
disp_group=nil

enough or should i individually remove images like

display.remove(myImage)
myImage = nil

Cell Game Labs
User offline. Last seen 5 years 48 weeks ago. Offline
Joined: 23 Jan 2011

Hey great post but just a little typo

1
local memUsed = (collectGarbage("count")) / 1000

"collectGarbage" needs a lowercase g for Garbage

so will be:

1
local memUsed = (collectgarbage("count")) / 1000

LairdGames
User offline. Last seen 41 weeks 2 days ago. Offline
Joined: 28 Oct 2011

Great post Danny! Thanks you for that. I am wondering about one thing: using Director, do I really need to remove images (inserted into groups) since I was in the impression that Director would do that for me when changing scene? Am I wrong to think that?

Mo

Danny
User offline. Last seen 2 years 35 weeks ago. Offline
Joined: 17 Aug 2011

@lairdGames, I haven't used director in over a year so I am unsure of it's current features. I'm sure if you posted that question in the director forums, you would get a proper answer however :)

LairdGames
User offline. Last seen 41 weeks 2 days ago. Offline
Joined: 28 Oct 2011

Thanks Danny, I will. I am using the Modify version 1.2 (short 15 lines code one)

Mo.

nml
User offline. Last seen 5 years 41 weeks ago. Offline
Joined: 18 Nov 2011

thanks for this post, i just needed this!

if i manage my transitions from an external module and not the storyboard scene, should i also cancel them between scene changes??

Antheor
User offline. Last seen 3 years 13 weeks ago. Offline
Joined: 22 Sep 2010

About 6)

What if I do something like :

1
2
3
4
local mytable={}
local function createBox()
    mytable.box = display.newImage("box.png")
end

Is it ok ?

DPN Sweden
User offline. Last seen 6 years 19 weeks ago. Offline
Joined: 26 Nov 2012

I've read all over the forum that when you remove the object it's EventLstener also get's removed so is this not the case?

1
2
3
4
5
6
7
8
9
10
local button = newImage("button.png")
 
local function Do Something()
--doing stuff
end
 
button:addEventListener("touch", DoSomething)
 
button:removeSelf();
button = nil;

In an example like this do I still need to remove it manually? Typing this next piece?

1
button:removeEventListener("touch", DoSomething)

I also want to get an answer to this question!

Danny
User offline. Last seen 2 years 35 weeks ago. Offline
Joined: 17 Aug 2011

@DPN Sweden,

When you remove an object any event listeners attached to it also get removed.
calling the following is enough

1
2
button:removeSelf() -- or display.remove( button )
button = nil

DPN Sweden
User offline. Last seen 6 years 19 weeks ago. Offline
Joined: 26 Nov 2012

Hi Danny
Okay thanks!

I am increasing my total memory use when I implement this, but the leakage remains constant. It would seem that Directors clean function takes care of my display objects like someone suspected. Time to look at media events instead.

ToeKnee
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 25 Nov 2012

Hi Noobie here,

So i am using Storyboard for my project.
I started testing memory by using the memusage function i found on the forums and it worked for me put it my main.lua file -
only thing it gives me the results every microsecond - thus spamming my terminal and as a result i can not see other print details which would help me progress through the test game procedure.

I want to try the storyboard.printMemUsage() - but can't get it to work - could someone provide an example of code format-
what goes in the Main.lua and what exactly you put on the scene.lua pages( is it need on all pages or just main?? - it's probably something simple but i'm missing it!

thanks
T

staytoooned
User offline. Last seen 2 years 20 weeks ago. Offline
Joined: 8 Sep 2010

When using "storyboard.printMemUsage()" I am maintaining approximately the same system & texture memory on the enterscene where I placed this. Is this memory accumulating or does it clear every time the scene gets purged?

---------MEMORY USAGE INFORMATION---------
System Memory Used: 1.627 Mb
Texture Memory Used: 40.177 Mb
------------------------------------------

Also, is the above a safe amount. My app is crashing at the same point in this scene on the iPad 1.

Also, I am inserting all display objects into the group. Do I manually have to remove & nil them or do they automatically get removed and nilled when the scene is purged?

Thanks.

ToeKnee
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 25 Nov 2012

Hi staytoooned -
Thats a good question - so me +1
This thread is about memory leaks - and it states between 1 to 8 above -but thats a change in memory - what is a good target to keep Sys memory /Tex memory under - and are there device differences?

I got the storyboard.printMemUsage working (on each scene page) and combined it with the purge on scene change.

storyboard.purgeOnSceneChange = true

this produces what i think is the total memory used to create the scene, and because the scene is purged when changed believe this to be the total Mem Used by my app at that point in time.

What i did notice is with Universal building - as i changed the Simulator between IPad and iPhone the Texture memory certainly grew!

This i put down to the graphics (@4x) etc.. but it would be handy to know Memory targets that are safe to be under for each device if possible?
T

staytoooned
User offline. Last seen 2 years 20 weeks ago. Offline
Joined: 8 Sep 2010

I still need to know if my display objects that I insert into the scene "group" automatically get purged (removed and nilled) when the scene gets purged with storyboard or do I manually have to removeSelf and nil them? In other words: Also, I am inserting all display objects into the group. Do I manually have to remove & nil them or do they automatically get removed and nilled when the scene is purged?

Please someone answer this question!

Rob Miracle
User offline. Last seen 7 hours 52 min ago. Offline
Staff
Joined: 26 Nov 2012

If you do a:

group:insert(somedisplayobject)

In your createScene(), willEnterScene() or enterscene() it will be purged and nil'ed when the scene is purged.

What is not removed is sound loaded in those scenes, timers, transitions that are not finished, any Runtime listeners (listeners on those display objects will be removed).

By default, storyboard scenes are only purged on low memory event warnings. You can turn on auto-purge, or purge the scene manually. In those cases memory should be cleaned up.

The iPad 1 only has 256M of memory and you at best can expect to get in the 40-80mb range on that device depending on what else it's doing.

Caleb P
User offline. Last seen 1 year 43 weeks ago. Offline
Joined: 5 May 2012

Do you have to use variables for timers and transitions, or do they nil out on their own?

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.