Storyboard: memUsage plateaus - Memory Leak or Normal Behavior?-- (Build: 2012.766)

//Memory Issue//

MemUsage: 101.5791015625 KB
Texture Usage 0.067584 MB

MemUsage: 102.1259765625 KB
Texture Usage 0.067584 MB

MemUsage: 102.1259765625 KB
Texture Usage 0.067584 MB

I am moving between two scenes, whilst always removing the last.
Example:

Scene1 --> Scene 2 (remove Scene 1 ) --> Back to Scene 1 (remove Scene 2)…etc.

Think of Scene 2 as a means of “resetting” Scene 1.

Is it normal for my overall memUsage to gradually accumulate, and then eventually level off?

(Note: I have to switch between the scenes a number of times before my usage will level off.)



How to reproduce:

If I activate my ‘reset’ button in Scene 1, and go to Scene 2:

function reset(event )  
 if event.phase == "began" then  
 storyboard.gotoScene( "scene2", "fade" )  
 return true  
 end  
end  

Once on Scene 2, I check for the last scene (Scene 1), remove it, and return back to a newly-generated Scene 1:

function scene:enterScene( event )  
 local group = self.view  
  
 local lastScene = storyboard.getPrevious()  
 storyboard.removeScene(lastScene)  
 storyboard.gotoScene( lastScene, "fade")  
  
end  

Back on the “new” Scene 1, I remove Scene 2*:

storyboard.removeScene(scene2)  

(Yes, I am adding and removing the listener for the reset button.)
[import]uid: 73951 topic_id: 23230 reply_id: 323230[/import]

Great question? Frankly I have the same issue but I am using the very short version of director. After say 5 or more switches the memory level seems to plateau. Not sure why because if it was a leak then I will think it would never plateau and eventually crash the device. On the other hand this behavior is strange since my understanding is switching should clean up the last screen unless something left behind. But then why after a bunch of switches the memory level stabilize?

I am sure we are missing something and would love someone can help on this.

Thanks for asking the question. I was going to. Also sorry for not having an answer for you.

Mo [import]uid: 49236 topic_id: 23230 reply_id: 92956[/import]

I agree. Even after stripping down my code to bare bones, I still get this issue. [import]uid: 73951 topic_id: 23230 reply_id: 92958[/import]

–Moved to 1st post-- [import]uid: 73951 topic_id: 23230 reply_id: 92970[/import]

me too, please help to slove this ! [import]uid: 22631 topic_id: 23230 reply_id: 92983[/import]

Well, about the getPrevious() function, it seems like a buggy behaviour. Try to create the simplest piece of code where you can reproduce that and if it persists, file it as a bug report.

About memory usage going up but then going down again, that’s a good sign, not a bad one. It probably means that garbage collection didn’t kick in, but when it does it removes what was unnecessary. Usually, when printing memory usage, you should call for garbage collection before printing, not sure if you’re doing that!

collectgarbage()  
print("Memory usage"...)  

If the memory usage goes too high before coming down again, you might want to add some forced garbage collection in specific points in your code.

Other than that I can only leave you with some recomendations about avoiding memory leaks on storyboard.

  • If you add event listeners on “enterScene”, you should remove them on “exitScene” and not “destroyScene”, or else everytime you enter a scene without it having been destroyed, you’re adding a new listener.

  • On “destroyScene” event, make sure you destroy all ongoing timers and transitions, and be sure to remove all listeners also, because if you only remove them on “exitScene”, when you destroy the scene from outside, the “exitScene” event won’t be called, resulting in listeners not being removed.

  • To help with managing timers and transitions, be sure to never call one without assigning it’s handler to some variable, so you can later remove them. What I usualy do is I create 2 tables, one for timers and other for transitions on each scene. Everytime I call for a transition or timer I add them there, all of them! On “destroyScene” I go through those tables and make sure to cancel everything that might be in progress.

Manuel [import]uid: 61899 topic_id: 23230 reply_id: 93013[/import]

“because if you only remove them on “exitScene”, when you destroy the scene from outside, the “exitScene” event won’t be called, resulting in listeners not being removed.”
If I remove all my listeners in exitScene first, then why would I have to worry about them not being removed in destroyScene? [import]uid: 73951 topic_id: 23230 reply_id: 93098[/import]

Memory usage going up and down is normal, especially during scene transitions because things like variables being created, new objects being created, brand new image files being loaded, etc. all contribute to higher memory usage.

When memory usage goes down slightly, it most-likely means some things were removed and then when memory usage seems to go down significantly then most-likely it means that Lua’s garbage collector kicked in (which removes all variables, etc. that are set to nil and have no references).

Garbage collection in Lua is automatic, and is pretty unpredictable, which is why you’ll see inconsistent behavior in terms of when the rising and falling of memory usage occurs. So that’s all normal behavior.

Also, in the storyboard sample, the memory usage that is outputted to the screen doesn’t represent an accurate account of memory usage for that scene, but rather, during that very moment when the text was printed. The best way to monitor memory usage is through an enterFrame listener, with the usage being printed out on every frame.

Once you have that in place, what you want to look out for is if while performing the same actions over and over again (over several different iterations), if memory usage is climbing and falling at about the same rate. If you notice that no matter how much times you repeat the same actions over and over again, that memory is continuing to climb (the lows continue to get higher and higher), then that could indicate a memory leak somewhere in the code of the actions you were performing.

Here’s a real-world example.

I was recently working on a project and decided to monitor memory usage once a certain feature was complete. The feature involved touching an object, and then being kicked over to a new screen to do something related to that object.

So to test for memory leaks I touched the object, and then touched the button that would bring me back to the new screen. Exited the screen, and kept repeating that process as I watched memory usage.

I began to notice that while memory usage would always go back down once I exited the secondary screen, the memory drop would always result in memory usage being 1kb higher than it was the previous time I repeated the steps.

Just in case, I made a mental note of that and just kept repeating the same exact actions and memory usage just kept going up by a mere 1kb every time I cycled through that action (and I made sure not to do anything “new” in my steps, to rule out the possibility of some other code causing a climb in memory usage).

I knew then, that there was a memory leak somewhere within that workflow. Sure enough, I “audited” the code that was responsible for those actions I was taking, made a few changes, and I was able to squash the small 1kb memory leak! (and a few other memory leaks related to some similar workflows).

And for those interested, this is the code I used to catch the memory leak (just stick it at the end of main.lua):

local function garbagePrinting() collectgarbage("collect") local memUsage_str = string.format( "memUsage = %.3f KB", collectgarbage( "count" ) ) print( memUsage_str ) local texMemUsage_str = system.getInfo( "textureMemoryUsed" ) texMemUsage_str = texMemUsage_str/1000000 texMemUsage_str = string.format( "texMemUsage = %.3f MB", texMemUsage_str ) print( texMemUsage_str )endRuntime:addEventListener( "enterFrame", garbagePrinting )[/code] [import]uid: 52430 topic_id: 23230 reply_id: 93192[/import]

Jonathan, thank you for your prompt reply.
My usage IS being checked via an enterFrame listener. I apologize for not specifying that in my original post.

I realize that fluctuations are normal as actions are being performed, and I am speaking of when all actions have been completed.

My usage appears to plateau and does not increase after a certain point (I know “plateau” implies this, but I’m just stressing this fact). Would this mean that I do NOT have a leak?
-Do you have any insight on what may be going wrong with getPrevious() ?
-Also, must one nil out any and all variable references before scene removal? [import]uid: 73951 topic_id: 23230 reply_id: 93195[/import]

Personally, I wouldn’t worry too much about the “plateau” effect you describe. I have noticed similar behavior in my current app, and I’m obsessive (borderline neurotic :wink: ) about clean coding and checking that everything is being cleaned up properly. I see a similar plateau effect, as in there is a slight memory jump in the early stages of the app run, but after a few repeat routines, it levels off and memory returns to the previous levels (often to the exact same numbers, to 3 decimal accuracy). This indicates to me that my app isn’t leaking.

What you should worry about, as Jonathan says, is if/when your memory levels *continue* to climb as you perform duplicate actions. For example, if you have a game with a “restart level” option, and every time you restart it the memory climbs beyond the previous low-value, then you probably have a memory leak.

In regards to all actions being complete, if the memory at the app start versus memory at app “end” is just barely lower, then you’re probably fine… personally, I would only worry about a memory level that goes up and up over time, because that will lead to eventual app slow down or an outright crash.

Brent Sorrentino
Ignis Design [import]uid: 9747 topic_id: 23230 reply_id: 93207[/import]

Thanks for your reply, I.D. .

I am in fact testing a “restart level” functionality. This is where I experience suspicious behavior.

I start with Scene 1, which contains a “reset” button.

I tap reset and go to Scene 2.

Scene 2 //removes// Scene 1

and return automatically to a “new” Scene 1 (and remove Scene 2).


Scene 1 --> Scene 2 (remove Scene 1) -->Scene 1 (remove Scene 2)

(Scene 2 is an intermediary scene used only to remove the last scene, in this case Scene 1.)

Each time I repeat this “reset” process I experience a slight increase in memUsage, until about the 4th or 5th time when it plateaus.

Example:
1st Time/Reset: 100.2 KB
2nd Time: 100.3 KB
3rd Time: 100.4 KB
4th Time: 100.4 KB
5th Time: 100.5 KB
6th Time: 100.5 KB and so on

(Note: I made these usage numbers up, but you get the point.)

This particular instance of “plateauing” is what I am concerned about.

Thanks again. [import]uid: 73951 topic_id: 23230 reply_id: 93219[/import]

Hi Mort,
In your example scenario, does the memory continue to climb past “100.5 KB” in the 10th repeat? The 20th repeat? The 50th? If it stays right around that level, it’s probably not reason for concern.

I am curious however… if you have a core scene which you’re looping back to (Scene 1), then a better approach might be cleaning that scene out internally, and never even go to a “cleaning” scene (Scene 2). I don’t know the structure of your game or what appears on each screen/scene, but ideally there should be a way to keep the user in Scene 1 and do your cleanup right there. I suppose you’d lose the auto-clean functionality of Storyboard/Director (for display objects) and you’d need to build your own cleanup function, but I’m fairly certain that approach would squash any memory leak issues you might have. :slight_smile:

Brent

[import]uid: 9747 topic_id: 23230 reply_id: 93302[/import]

Brent,

I’ll double check and see if my usage eventually starts increasing again. I am pretty sure it does not though. Let’s hope what I’m seeing is normal.

I don’t want to lose the auto-clean functionality of Storyboard, but thanks for your suggestion and help!

EDIT: Also, I resolved my getPrevious() issue. The lastScene is now getting reported correctly.

Strangely enough, not wrapping my storyboard.gotoScene(), in a timer.performWithDelay() or a generic function() (whist inside enterScene(), for example), caused a whole host of problems: transition glitches, etc.

Moral of the story is: don’t just drop a storyboard.gotoScene(x) in storyboard.enterScene() without first wrapping it something else.


Also, if you have getPrevious() checking your last scene when no such scene exists (at least yet), then be sure to precede it with a check for whether it’s nil.

local lastScene = storyboard.getPrevious()  
if lastScene ~= nil then  
print("Removing: "..lastScene)  
storyboard.removeScene(lastScene )  
end  

If I am incorrect about any of this, please correct me! [import]uid: 73951 topic_id: 23230 reply_id: 93429[/import]

Now, I’ve got it to the point where my memory plateaus immediately upon returning to my original scene.

My usage ends up “slightly” higher than when I had no Scene2, and does NOT increase no matter how many times I repeat my “reset”.
On Start @ Scene 1: MemUsage: 98.978515625 KB
Once I’ve gone to Scene 2, removed Scene 1, returned back to a new Scene 1, and removed Scene 2:

MemUsage: 99.251953125 KB

[import]uid: 73951 topic_id: 23230 reply_id: 93433[/import]

Based on your latest version, I’d say that your app is now 100% fine: no memory leaks. :slight_smile: My app memory also increases just slightly in the beginning, as I load or move among new scenes. After that initial increase, it quickly levels off to a general range and the memory doesn’t increase beyond that. [import]uid: 9747 topic_id: 23230 reply_id: 93437[/import]

Great! Thanks for all your help, Jonathan and Brent. [import]uid: 73951 topic_id: 23230 reply_id: 93626[/import]