audio management to avoid memory leak

Hi

I have question about audio management, been reading this articles about audio handling but still bit confuse, if i have this kind of script

local storyboard        = require "storyboard" local scene             = storyboard.newScene() function scene:createScene(event) local screenGroup     = self.view local backgroundmusic = audio.loadStream("music.ogg") audio.play(backgroundmusic, {loops=-1}) local menuBtn = display.newImage('images/airakawaii\_games\_pause.png') menuBtn.x             = 460 menuBtn.y             = 300 screenGroup:insert(menuBtn) function menuBtn:tap() audio.stop() audio.dispose(backgroundmusic) backgroundmusic = nil storyboard.purgeScene( "game.lua" ) storyboard.removeScene( "game.lua" ) storyboard.gotoScene( "menu.lua" ) end menuBtn:addEventListener("tap",menuBtn) end function scene:enterScene(event) end function scene:exitScene(event) audio.stop() audio.dispose(backgroundmusic) backgroundmusic = nil storyboard.purgeScene( "game.lua" ) storyboard.removeScene( "game.lua" ) end function scene:destroyScene(event) end scene:addEventListener("createScene", scene) scene:addEventListener("enterScene", scene) scene:addEventListener("exitScene", scene) scene:addEventListener("destroyScene", scene) return scene   

look at function menuBtn:tap() and function scene:exitScene(event) do i must do that twice on both area or need only one time? and which area that correct, i mean to avoid memory leak

because when i try to debug using this code

local function checkMemory()    collectgarbage( "collect" )    local memUsage\_str = string.format( "MEMORY = %.3f KB", collectgarbage( "count" ) )    print( memUsage\_str, "TEXTURE = "..(system.getInfo("textureMemoryUsed") / (1024 \* 1024) ) ) end timer.performWithDelay( 1000, checkMemory, 0 )  

I check when i goes to menu > start game > click menu button > back to menu > back to game (turn around and round) the memory that game consume is higher and higher, is that normal?

Is the code above “game.lua” by any chance? 

There are quite a few things that need addressed in this block of code.  Bear with me.

  1.  You need to understand when storyboard scenes fire and when they don’t.  createScene() fires under three circumstances:

  2. It’s the very first time the scene loads.

  3. The scene has been purged.

  4. The scene has been removed.

In the case of #2, scenes can be purged in two circumstances, you did it by calling storyboard.purgeScene() or storyboard.purgeAll() or there was a low memory event that purged some unused scene.

 

In the case of #3, scenes are only removed when you instruct them too by calling storyboard.removeScene() or storyboard.removeAll().  If you remove a scene you do not need to purge it.  

 

enterScene() fires every time the scene is entered as well as exitScene().  The destroyScene() is more like createScene() in that it only fires when storyboard.purgeScene, .purgeAll, .removeScene, or .removeAll is called on that function.

 

So let’s look at a scenario.  You run this scene for the first time.  Your background track is loaded and starts playing in the createScene event (which could start playing the music before the scene is transitioned on the screen!).   You now leave the scene and the code in exitScene() disposes of the audio as you have instructed it to do.  Now later you come back. You won’t have background audio because createScene() doesn’t fire (that’s why you’re trying to do all those purges/removes more on that in a bit).   You leave the scene again and try to dispose of the background audio and you crash and get an error because the audio is not there.  

 

Therefore, it is best to load the audio in enterScene() and not createScene().  This leads to the second problem.

 

  1. You are making your background sound “local” in createScene().  This scopes the variable so that it’s only available in createScene().  I suspect your getting a nil error in your exitScene unless you have somewhere else made “backgroundmusic” a global variable.  For variables that need to be referenced in multiple storyboard functions, its best to declare the variable at the top outside of any of the storyboard functions.  Maybe something like:

    local storyboard        = require “storyboard” local scene             = storyboard.newScene()   local backgroundmusic

Then when you move the music loading code to enterScene() (which you should, or if you insist on leaving it in createScene …) , just leave the local off of it then since you already declared it at the top.

 

  1. You can’t purge or remove the scene you are in like you are doing in your button handler.  Assuming this is game.lua, the scene has to be on the screen, you can’t destroy what’s there.  I’ve heard that you can get away with this in exitScene() since at that point, the scene has left the screen.  Still I don’t like trying to remove the scene you’re in.  It’s best in say menu.lua to purge or remove the scene before you go to it.  You can also turn on auto purging by setting a storyboard flag.  I don’t remember it off the top of my head but it’s in the docs.

  2.  You don’t need to purge and remove both.   Purging removes the scene’s “view”, that is the display.newGroup() that holds all the things on the screen.  Once a scene is purged, createScene() will fire the next time the scene is loaded and all the things that happen there will re-fire.  This is likely why you are trying to purge game.lua because your sound wasn’t reloading for you.

Removing on the other hand completely removes the module from memory.  This is something people find they need to do when they have things going on when the scene is loaded but not inside one of the scene functions.   In you’re case, there is nothing going on in the scene’s main chunk that needs to be reset, so for now with all your activity being inside of storyboard scene functions, no need to use removeScene().

  1. sound remove code in the button handler or in exitScene() or both?  Well for now, because only the createScene() function and any children functions are the only ones to know that the variable backgroundmusic exists, you kinda have to do it in the button handler.  Though I would think it’s better in exitScene().  You don’t need it in both.   But the exitScene() one won’t work until you fix your scope problem talked about in #2.

Now for memory leaks, really you shouldn’t have any if you can successfully dispose of the sound and right now your button is disposing it and you shouldn’t be having leaks.  

Is the code above “game.lua” by any chance? 

There are quite a few things that need addressed in this block of code.  Bear with me.

  1.  You need to understand when storyboard scenes fire and when they don’t.  createScene() fires under three circumstances:

  2. It’s the very first time the scene loads.

  3. The scene has been purged.

  4. The scene has been removed.

In the case of #2, scenes can be purged in two circumstances, you did it by calling storyboard.purgeScene() or storyboard.purgeAll() or there was a low memory event that purged some unused scene.

 

In the case of #3, scenes are only removed when you instruct them too by calling storyboard.removeScene() or storyboard.removeAll().  If you remove a scene you do not need to purge it.  

 

enterScene() fires every time the scene is entered as well as exitScene().  The destroyScene() is more like createScene() in that it only fires when storyboard.purgeScene, .purgeAll, .removeScene, or .removeAll is called on that function.

 

So let’s look at a scenario.  You run this scene for the first time.  Your background track is loaded and starts playing in the createScene event (which could start playing the music before the scene is transitioned on the screen!).   You now leave the scene and the code in exitScene() disposes of the audio as you have instructed it to do.  Now later you come back. You won’t have background audio because createScene() doesn’t fire (that’s why you’re trying to do all those purges/removes more on that in a bit).   You leave the scene again and try to dispose of the background audio and you crash and get an error because the audio is not there.  

 

Therefore, it is best to load the audio in enterScene() and not createScene().  This leads to the second problem.

 

  1. You are making your background sound “local” in createScene().  This scopes the variable so that it’s only available in createScene().  I suspect your getting a nil error in your exitScene unless you have somewhere else made “backgroundmusic” a global variable.  For variables that need to be referenced in multiple storyboard functions, its best to declare the variable at the top outside of any of the storyboard functions.  Maybe something like:

    local storyboard        = require “storyboard” local scene             = storyboard.newScene()   local backgroundmusic

Then when you move the music loading code to enterScene() (which you should, or if you insist on leaving it in createScene …) , just leave the local off of it then since you already declared it at the top.

 

  1. You can’t purge or remove the scene you are in like you are doing in your button handler.  Assuming this is game.lua, the scene has to be on the screen, you can’t destroy what’s there.  I’ve heard that you can get away with this in exitScene() since at that point, the scene has left the screen.  Still I don’t like trying to remove the scene you’re in.  It’s best in say menu.lua to purge or remove the scene before you go to it.  You can also turn on auto purging by setting a storyboard flag.  I don’t remember it off the top of my head but it’s in the docs.

  2.  You don’t need to purge and remove both.   Purging removes the scene’s “view”, that is the display.newGroup() that holds all the things on the screen.  Once a scene is purged, createScene() will fire the next time the scene is loaded and all the things that happen there will re-fire.  This is likely why you are trying to purge game.lua because your sound wasn’t reloading for you.

Removing on the other hand completely removes the module from memory.  This is something people find they need to do when they have things going on when the scene is loaded but not inside one of the scene functions.   In you’re case, there is nothing going on in the scene’s main chunk that needs to be reset, so for now with all your activity being inside of storyboard scene functions, no need to use removeScene().

  1. sound remove code in the button handler or in exitScene() or both?  Well for now, because only the createScene() function and any children functions are the only ones to know that the variable backgroundmusic exists, you kinda have to do it in the button handler.  Though I would think it’s better in exitScene().  You don’t need it in both.   But the exitScene() one won’t work until you fix your scope problem talked about in #2.

Now for memory leaks, really you shouldn’t have any if you can successfully dispose of the sound and right now your button is disposing it and you shouldn’t be having leaks.