Memory Problems when Changing Scenes

Hello!  I am new to Corona and have created a 27page interactive children’s book.  I am using the Photoshop plugin, Kwik which has been amazing.  I am done with the app, but am now having problems with crashes on the iPad and iPhone due to memory.  The app runs fine in the simulator on the Mac but crashes about every 2-3 pages (scenes) on the iPad2 and about ever 6-7 pages on the iPhone 5.  I had the app running fine on the iPad about a month ago but since then there have been software upgrades with both Corona and Kwik AND I have also added quite a few more images and audio to the app and now it is crashing regularly.  

The odd thing is,that a month ago, before I completed software upgrades, the app was an enormous 2GB in size.  (I hadn’t learned about image compression yet!)  Even at the 2GB size, the app ran without crashing.  Now I have upgraded the software and have added even more images and audio, but with compression, I have reduced the size to 70MB.  

The only time the app crashes is when I am going from one page (scene) to another.  My thoughts are that somewhere in these upgrades the software changed and it is disposing of scenes differently and perhaps not disposing of everything it needs to before going to the next page.  I share very few elements between all of the pages so at every page turn, it should be disposing of almost everything.  I have attached the code from just one of my 27 pages to see if anyone can recognize issues at the end where it is canceling timers etc and changing to a new page (scene.) 

I have some audio that plays in timers and I was wondering if I should cancel the timers, tweens etc.  before disposing of the audio.   Any thoughts would be greatly appreciated!!!   :slight_smile:

Christi

Hi Christi,

Are these timers intended to play audio at some future point, but before that point, you dispose of the audio? If so, you should definitely stop those timers before disposing of the audio. In fact, you should cancel all timers/tweens that aren’t intended, and make sure that their references are being cleanup up too. Tracking down memory leaks can be a real pain, but it seems like you have some potential suspicion on what may be causing this.

Best regards,

Brent

Thanks for the response Brent. 

Were you able to see the attached code?  If not, I have pasted the bottom part of the code below.  

I would appreciate any comments you have about the disposal of the page (scene.)

Thanks so much!

Christi

[lua]–

       – (BOTTOM) External code will render here 

   end --ends phase did 

end – ends scene:show

function scene:hide( event ) 

   – all disposal happens here 

   if event.phase == “will” then 

          if audio.isChannelActive ( 1 ) then 

             audio.stop(1); 

          end 

          audio.dispose(allAudios.pageflip); allAudios.pageflip = nil 

          if audio.isChannelActive ( 2 ) then 

             audio.stop(2); 

          end 

          audio.dispose(allAudios.flagin); allAudios.flagin = nil 

          if audio.isChannelActive ( 3 ) then 

             audio.stop(3); 

          end 

          audio.dispose(allAudios.button17); allAudios.button17 = nil 

          if audio.isChannelActive ( 5 ) then 

             audio.stop(5); 

          end 

          audio.dispose(allAudios.funk_guitar_rif); allAudios.funk_guitar_rif = nil 

          if audio.isChannelActive ( 6 ) then 

             audio.stop(6); 

          end 

          audio.dispose(allAudios.button27); allAudios.button27 = nil 

          if audio.isChannelActive ( 10 ) then 

             audio.stop(10); 

          end 

          audio.dispose(allAudios.magic_bell_3); allAudios.magic_bell_3 = nil 

       if (allAudios.paintbrush_singx9 ~= 0 and allAudios.paintbrush_singx9 ~= nil) then audio.stop(allAudios.paintbrush_singx9); allAudios.paintbrush_singx9 = nil end; audio.dispose(allAudios.paintbrush_sing); allAudios.paintbrush_sing = nil;  

       if (allAudios.firework_mediumx9 ~= 0 and allAudios.firework_mediumx9 ~= nil) then audio.stop(allAudios.firework_mediumx9); allAudios.firework_mediumx9 = nil end; audio.dispose(allAudios.firework_medium); allAudios.firework_medium = nil;  

          if audio.isChannelActive ( 7 ) then 

             audio.stop(7); 

          end 

          audio.dispose(allAudios.pull_cord_style); allAudios.pull_cord_style = nil 

          if audio.isChannelActive ( 13 ) then 

             audio.stop(13); 

          end 

          audio.dispose(allAudios.cheering9sec); allAudios.cheering9sec = nil 

       if (allAudios.zipper_1x9 ~= 0 and allAudios.zipper_1x9 ~= nil) then audio.stop(allAudios.zipper_1x9); allAudios.zipper_1x9 = nil end; audio.dispose(allAudios.zipper_1); allAudios.zipper_1 = nil;  

          if audio.isChannelActive ( 15 ) then 

             audio.stop(15); 

          end 

          audio.dispose(allAudios.bechamp2final); allAudios.bechamp2final = nil 

          if audio.isChannelActive ( 17 ) then 

             audio.stop(17); 

          end 

          audio.dispose(allAudios.bechamp4final); allAudios.bechamp4final = nil 

          if audio.isChannelActive ( 18 ) then 

             audio.stop(18); 

          end 

          audio.dispose(allAudios.bechamp5final); allAudios.bechamp5final = nil 

          if audio.isChannelActive ( 14 ) then 

             audio.stop(14); 

          end 

          audio.dispose(allAudios.bechamp1final); allAudios.bechamp1final = nil 

          if audio.isChannelActive ( 18 ) then 

             audio.stop(18); 

          end 

          audio.dispose(allAudios.bechamp3final); allAudios.bechamp3final = nil 

       if (allAudios.whipwhoosh03x9 ~= 0 and allAudios.whipwhoosh03x9 ~= nil) then audio.stop(allAudios.whipwhoosh03x9); allAudios.whipwhoosh03x9 = nil end; audio.dispose(allAudios.whipwhoosh03); allAudios.whipwhoosh03 = nil;  

          Runtime:removeEventListener(“enterFrame”, composer.kClean) 

       composer.cancelAllTweens(); composer.cancelAllTransitions(); 

          physics.stop() 

          composer.cancelAllTimers(); 

   elseif event.phase == “did” then 

          composer.test = nil 

   end 

end  

function scene:destroy( event ) 

   – Remove all unecessary composer items 

   composer.mt_kwkconf_blcir = nil 

   layer.gp_kwkconf_blcir:removeSelf(); layer.gp_kwkconf_blcir = nil 

   composer.mt_kwkconf_redcir = nil 

   layer.gp_kwkconf_redcir:removeSelf(); layer.gp_kwkconf_redcir = nil 

   composer.mt_kwkconf_staror = nil 

   layer.gp_kwkconf_staror:removeSelf(); layer.gp_kwkconf_staror = nil 

   composer.mt_kwkconf_ciryel = nil 

   layer.gp_kwkconf_ciryel:removeSelf(); layer.gp_kwkconf_ciryel = nil 

   composer.mt_kwkconf_sqpink = nil 

   layer.gp_kwkconf_sqpink:removeSelf(); layer.gp_kwkconf_sqpink = nil 

   composer.mt_kwkconfsqbl = nil 

   layer.gp_kwkconfsqbl:removeSelf(); layer.gp_kwkconfsqbl = nil 

   composer.mt_kwkconf_sqrppl = nil 

   layer.gp_kwkconf_sqrppl:removeSelf(); layer.gp_kwkconf_sqrppl = nil 

   composer.mt_kwkconf_starbl = nil 

   layer.gp_kwkconf_starbl:removeSelf(); layer.gp_kwkconf_starbl = nil 

   composer.mt_kwkconf_stargr = nil 

   layer.gp_kwkconf_stargr:removeSelf(); layer.gp_kwkconf_stargr = nil 

   composer.kClean = nil 

end 

scene:addEventListener( “create”, scene ) 

scene:addEventListener( “show”, scene ) 

scene:addEventListener( “hide”, scene ) 

scene:addEventListener( “destroy”, scene ) 

return scene 

[/lua]

Hi @christi,

As a general suggestion, I think you should find a better way to manage/organize your audio files, so it’s easier to clean them all up without all the manual line-by-line code. For example, store the references inside a table, and then loop through that table when you need to dispose and nil out the handles.

This tutorial may get you started:

http://coronalabs.com/blog/2013/06/04/tutorial-handling-cross-scene-audio/

Also, you shouldn’t bother with checking “isChannelActive” all the time. I suggest you just stop all channels in one line (don’t pass a channel number to the function, and Corona will just stop all channels).

Take care,

Brent

Hi Christi,

Are these timers intended to play audio at some future point, but before that point, you dispose of the audio? If so, you should definitely stop those timers before disposing of the audio. In fact, you should cancel all timers/tweens that aren’t intended, and make sure that their references are being cleanup up too. Tracking down memory leaks can be a real pain, but it seems like you have some potential suspicion on what may be causing this.

Best regards,

Brent

Thanks for the response Brent. 

Were you able to see the attached code?  If not, I have pasted the bottom part of the code below.  

I would appreciate any comments you have about the disposal of the page (scene.)

Thanks so much!

Christi

[lua]–

       – (BOTTOM) External code will render here 

   end --ends phase did 

end – ends scene:show

function scene:hide( event ) 

   – all disposal happens here 

   if event.phase == “will” then 

          if audio.isChannelActive ( 1 ) then 

             audio.stop(1); 

          end 

          audio.dispose(allAudios.pageflip); allAudios.pageflip = nil 

          if audio.isChannelActive ( 2 ) then 

             audio.stop(2); 

          end 

          audio.dispose(allAudios.flagin); allAudios.flagin = nil 

          if audio.isChannelActive ( 3 ) then 

             audio.stop(3); 

          end 

          audio.dispose(allAudios.button17); allAudios.button17 = nil 

          if audio.isChannelActive ( 5 ) then 

             audio.stop(5); 

          end 

          audio.dispose(allAudios.funk_guitar_rif); allAudios.funk_guitar_rif = nil 

          if audio.isChannelActive ( 6 ) then 

             audio.stop(6); 

          end 

          audio.dispose(allAudios.button27); allAudios.button27 = nil 

          if audio.isChannelActive ( 10 ) then 

             audio.stop(10); 

          end 

          audio.dispose(allAudios.magic_bell_3); allAudios.magic_bell_3 = nil 

       if (allAudios.paintbrush_singx9 ~= 0 and allAudios.paintbrush_singx9 ~= nil) then audio.stop(allAudios.paintbrush_singx9); allAudios.paintbrush_singx9 = nil end; audio.dispose(allAudios.paintbrush_sing); allAudios.paintbrush_sing = nil;  

       if (allAudios.firework_mediumx9 ~= 0 and allAudios.firework_mediumx9 ~= nil) then audio.stop(allAudios.firework_mediumx9); allAudios.firework_mediumx9 = nil end; audio.dispose(allAudios.firework_medium); allAudios.firework_medium = nil;  

          if audio.isChannelActive ( 7 ) then 

             audio.stop(7); 

          end 

          audio.dispose(allAudios.pull_cord_style); allAudios.pull_cord_style = nil 

          if audio.isChannelActive ( 13 ) then 

             audio.stop(13); 

          end 

          audio.dispose(allAudios.cheering9sec); allAudios.cheering9sec = nil 

       if (allAudios.zipper_1x9 ~= 0 and allAudios.zipper_1x9 ~= nil) then audio.stop(allAudios.zipper_1x9); allAudios.zipper_1x9 = nil end; audio.dispose(allAudios.zipper_1); allAudios.zipper_1 = nil;  

          if audio.isChannelActive ( 15 ) then 

             audio.stop(15); 

          end 

          audio.dispose(allAudios.bechamp2final); allAudios.bechamp2final = nil 

          if audio.isChannelActive ( 17 ) then 

             audio.stop(17); 

          end 

          audio.dispose(allAudios.bechamp4final); allAudios.bechamp4final = nil 

          if audio.isChannelActive ( 18 ) then 

             audio.stop(18); 

          end 

          audio.dispose(allAudios.bechamp5final); allAudios.bechamp5final = nil 

          if audio.isChannelActive ( 14 ) then 

             audio.stop(14); 

          end 

          audio.dispose(allAudios.bechamp1final); allAudios.bechamp1final = nil 

          if audio.isChannelActive ( 18 ) then 

             audio.stop(18); 

          end 

          audio.dispose(allAudios.bechamp3final); allAudios.bechamp3final = nil 

       if (allAudios.whipwhoosh03x9 ~= 0 and allAudios.whipwhoosh03x9 ~= nil) then audio.stop(allAudios.whipwhoosh03x9); allAudios.whipwhoosh03x9 = nil end; audio.dispose(allAudios.whipwhoosh03); allAudios.whipwhoosh03 = nil;  

          Runtime:removeEventListener(“enterFrame”, composer.kClean) 

       composer.cancelAllTweens(); composer.cancelAllTransitions(); 

          physics.stop() 

          composer.cancelAllTimers(); 

   elseif event.phase == “did” then 

          composer.test = nil 

   end 

end  

function scene:destroy( event ) 

   – Remove all unecessary composer items 

   composer.mt_kwkconf_blcir = nil 

   layer.gp_kwkconf_blcir:removeSelf(); layer.gp_kwkconf_blcir = nil 

   composer.mt_kwkconf_redcir = nil 

   layer.gp_kwkconf_redcir:removeSelf(); layer.gp_kwkconf_redcir = nil 

   composer.mt_kwkconf_staror = nil 

   layer.gp_kwkconf_staror:removeSelf(); layer.gp_kwkconf_staror = nil 

   composer.mt_kwkconf_ciryel = nil 

   layer.gp_kwkconf_ciryel:removeSelf(); layer.gp_kwkconf_ciryel = nil 

   composer.mt_kwkconf_sqpink = nil 

   layer.gp_kwkconf_sqpink:removeSelf(); layer.gp_kwkconf_sqpink = nil 

   composer.mt_kwkconfsqbl = nil 

   layer.gp_kwkconfsqbl:removeSelf(); layer.gp_kwkconfsqbl = nil 

   composer.mt_kwkconf_sqrppl = nil 

   layer.gp_kwkconf_sqrppl:removeSelf(); layer.gp_kwkconf_sqrppl = nil 

   composer.mt_kwkconf_starbl = nil 

   layer.gp_kwkconf_starbl:removeSelf(); layer.gp_kwkconf_starbl = nil 

   composer.mt_kwkconf_stargr = nil 

   layer.gp_kwkconf_stargr:removeSelf(); layer.gp_kwkconf_stargr = nil 

   composer.kClean = nil 

end 

scene:addEventListener( “create”, scene ) 

scene:addEventListener( “show”, scene ) 

scene:addEventListener( “hide”, scene ) 

scene:addEventListener( “destroy”, scene ) 

return scene 

[/lua]

Hi @christi,

As a general suggestion, I think you should find a better way to manage/organize your audio files, so it’s easier to clean them all up without all the manual line-by-line code. For example, store the references inside a table, and then loop through that table when you need to dispose and nil out the handles.

This tutorial may get you started:

http://coronalabs.com/blog/2013/06/04/tutorial-handling-cross-scene-audio/

Also, you shouldn’t bother with checking “isChannelActive” all the time. I suggest you just stop all channels in one line (don’t pass a channel number to the function, and Corona will just stop all channels).

Take care,

Brent