Corona Composer - game slows / drop in FPS after changing scenes.

Hi all, wonder if you can help me…

I’ve been using Corona for a few months now and loving it…

However, everything I create (3 demo games so far) as soon as I adopt the composer and start using multiple scenes the fps drops over time.

Its obviously something fundamental Im doing wrong.

for example…

I start with main.lua which goes straight to composer.gotoScene(“scene_menu”) - not much going on here - just a button at the moment, so all is well.

the menu takes you to the game, composer.gotoScene(“scene_game”) - you play the game, and the first time you play all is well - it plays at a solid 60 fps.

the player dies -  composer.gotoScene(“scene_gameover”) - again not much going on - just a button which takes you back to the start menu.

this is when the trouble starts, if you go through the process again and play the game again - the fps begin to drop each time, next time you play the game runs at 50 fps, next time its around 40 fps, next time its around 20-30 fps. classic memory leak.

I’ve been reading up on lua scope thinking this is surely the issue (being new to lua - its bound to be me just not defining / clearing stuff properly).

I dont use globals (following reading Goodbye Globals - well i do, but i use the method recommended).

I’ve tried declaring all my local variables / functions within the function scene:create( event ) - in the hope it would fully clear them when I remove the scene (using composer.removeScene / composer.recycleOnSceneChange). But the fps still drops.

so im thinking that must be an incorrect method, I’ve now took to forward declaring everything at the start (before function scene:create( event )). Then later i’ve gone through every display object created and using removeSelf() and setting it back to nil (although Im sure you dont have to do this if you if you use sceneGroup:insert ?).

Im now going through and setting every variable created back to nil  (just in case), cancelling all the timers - but still no joy.

Basically Im grabbing at straws trying different things - with little joy.

the strange thing is the texture memory is a constant 2.54mb during the game and doesn’t climb and the Memory Usage is between 0.6mb and 1.5mb, it climbs to about 1.5mb then drops to 0.6mb, this happens on each game whether it is 20 fps or 60 fps.

So it seems to be something else.? its got me stumped.

The simulator gives me a solid 60 fps - no matter how many times I play the game.

The test device is a Samsung Tablet.

Im confident its something Im doing wrong / there is something simple Im missing. I will post some of the game code in its current state below. 

thanks in advance for any tips…

local composer = require( "composer" ) local scene = composer.newScene() local physics = require( "physics" ) local perspective = require("perspective") local timer2 = require("timer2") local Car = require("Car") local OtherCar = require("OtherCar") local Global = require( "GlobalData" ) physics.start() -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()"- -- ----------------------------------------------------------------------------------- -- \>\> Forward Declare LOCAL Variables - SEE IF IT STOPS THE FPS DROP! -- \>\> Forward Declare FUNCTIONS. local dt = 1000 / display.fps local last\_ms = 0 math.randomseed(os.time()) local random = math.random -- \>\>\> Make a movable Camera Spot - to track. -- CONSTANT VALUES local \_CX = display.contentWidth\*0.5 local \_CY = display.contentHeight\*0.5 local \_CW = display.contentWidth local \_CH = display.contentHeight local \_T = display.screenOriginY -- Top local \_L = display.screenOriginX -- Left local \_R = display.viewableContentWidth - \_L -- Right local \_B = display.viewableContentHeight - \_T-- Bottom local camera local CameraPoint -- ------------------------------------------------------------------------------- -- \>\>\> Setup Tables local the\_Images = {} local the\_Object = {} local BackgroundEndless = {} local ScrollItemsX = {} local ScrollItemsY = {} local ScrollItemsXdist = {} local ScrollItemsYdist = {} local BackgroundObj1 local distancetravelled = 0 local nextcar local fingametimer local finrect local damagebouncespeed local damagebounce = 0 local displayInfo -- \>\>\> setup GLOBALS Global.backgroundspeed = 3 Global.directionstart = 0 Global.controllerdirection = 0 Global.lastspeed = 0 Global.lastdistance = 0 Global.laneoccupied = {} for j = 1, 7 do Global.laneoccupied[j] = 0 end -- \>\>\> setup TIMERS & transistions local camstarttimer local othercartimer local bouncespeed -- \>\>\> setup FUNCTIONS local on\_enterFrame local generateothercar local onCollision local finishgame local turnoffdamage local fingam -- \>\>\> setup players local player local othercar = {} -- \>\>\> get the graphic filenames local the\_GraphicFileNames = { "freeway.png", "freeway2.png"} -- more GRAPHICS to be added when done hence table. -- \>\>\> load in the images for j = 1, #the\_GraphicFileNames do the\_Images[the\_GraphicFileNames[j]] = { type="image", filename="images/".. the\_GraphicFileNames[j] } -- more GRAPHICS to be added hence table !! end -- functions turnoffbounce = function () bounce = 0 end finishgame = function() fingam = function() Global.GameOver = 1 displayInfo:removeSelf() displayInfo = nil for j = 1, #othercar do othercar[j]:removeSelf() othercar[j] = 0 end othercar = {} othercar = nil player = nil camera:destroy() -- ALWAYS NEEDED TO REMOVE OBJECTS OFF SCREEN. camera = nil Runtime:removeEventListener( "collision", onCollision ) Runtime:removeEventListener( "enterFrame", on\_enterFrame ) onCollision = nil on\_enterFrame = nil display.remove(displayInfo) displayInfo = nil timer.cancel(fingametimer) timer.cancel(camstarttimer) timer.cancel(othercartimer) timer.cancel(bouncespeed) camstarttimer = nil othercartimer = nil bouncespeed = nil fingametimer = nil display.getCurrentStage():setFocus( nil ) composer.gotoScene("scene-gameover") end fingametimer = timer.performWithDelay(2000, fingam) end -- "scene:create()" function scene:create( event ) local sceneGroup = self.view -- Initialize the scene here -- Example: add display objects to "sceneGroup", add touch listeners, etc. -- \>\>\> Build Camera camera = perspective.createView() camera:setBounds(display.contentCenterX, display.contentCenterX\*1.44,false, false) -- Lock X axis to screen limits camera:toPoint(128, 284) -- Change the cameras focus to an X,Y point CameraPoint = display.newRect( 128, 284, 10, 10 ) CameraPoint:setFillColor( 255,0,0 ) CameraPoint.alpha = 0 CameraPoint.x = \_CX CameraPoint.y = \_CH camera:add(CameraPoint, 1) camera:setMasterOffset((\_CW-256)\*0.5, 150) camera.damping = 1 -- A bit more fluid tracking camera:setFocus(CameraPoint) -- Set the focus to the player camera:track() camstarttimer = timer.performWithDelay( 1000, function() camera.damping = 20; end, 1 , "TimerRunning", false ) -- \>\>\> setup newRects in scene in the correct location -- Endless Background Object 18 BackgroundObj1 = display.newRect(0,0,312,515) -- make slightly over in height to avoid black lines BackgroundObj1.fill = the\_Images["freeway.png"] BackgroundObj1.anchorX = 0 BackgroundObj1.anchorY = 0 BackgroundEndless[#BackgroundEndless+1] = BackgroundObj1 -- more backgrounds to be added hence table !! sceneGroup:insert( BackgroundObj1 ) camera:add(BackgroundObj1 , 3) -- add to camera level for j = 1, #the\_GraphicFileNames do the\_Images[the\_GraphicFileNames[j]] = nil end displayInfo = display.newText("Speed: - MPH" , \_CX, 20, native.systemFontBold, 12) displayInfo:toFront( ) -- \>\>\> Add Camera to Player camera:prependLayer() -- \>\>\> Set the Parallax Settings camera:setParallax(1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3) -- Here we set parallax for each layer in descending order CameraPoint:toFront( ) player = Car:new() player.damage = 0 player.x = CameraPoint.x - (player.width \* 0.25) player.y = CameraPoint.y sceneGroup:insert(player) camera:add(player,2) generateothercar = function () local lanefullcount = 0 for j = 1, 6 do if Global.laneoccupied[j] == 1 then lanefullcount = lanefullcount + 1 end end if lanefullcount == 6 then return end -- all lanes full nextcar = #othercar othercar[nextcar] = OtherCar:new() othercar[nextcar]:start(true) sceneGroup:insert(othercar[nextcar]) camera:add(othercar[nextcar],2) camera:add(othercar[nextcar].num,2) camera:add(othercar[nextcar].num2,2) end othercartimer = timer.performWithDelay(2500, generateothercar, -1) onCollision = function (event) if event.object1.id == "player" and event.object2.id == "powerup" then Global.backgroundspeed = Global.backgroundspeed + 0.05 if bounce == 0 then bouncespeed = transition.to( displayInfo, { time=100, xScale=1.3, yScale=1.3 } ); transition.to( displayInfo, { time=100, delay = 100, xScale=1, yScale=1, onComplete=turnoffbounce} ); bounce = 1; end end if event.object1.id == "powerup" and event.object2.id == "player" then Global.backgroundspeed = Global.backgroundspeed + 0.05 end if event.object1.id == "player" and event.object2.id == "othercar" then player.damage = player.damage + random(10,30) if player.damage \>= 100 then player.damage = 100 end if player.y \> 530 then player.damage = 100 end Global.backgroundspeed = Global.backgroundspeed - 0.5 if Global.backgroundspeed \< 2.5 then Global.backgroundspeed = 2.5 end if player.damage \>= 100 then finishgame() end end if event.object1.id == "othercar" and event.object2.id == "player" then player.damage = player.damage + random(10,30) if player.damage \>= 100 then player.damage = 100 end if player.y \> 530 then player.damage = 100 end Global.backgroundspeed = Global.backgroundspeed - 0.5 if Global.backgroundspeed \< 2.5 then Global.backgroundspeed = 2.5 end if player.damage \>= 100 then finishgame() end end end Runtime:addEventListener( "collision", onCollision ) -- \>\>\> Set the Endless Background Update and Checks on\_enterFrame = function ( event ) if player.y \> 455 and Global.backgroundspeed \> 3 then player.y = player.y -1 end distancetravelled = distancetravelled + (((((Global.backgroundspeed\* 20)\*0.01666)\*0.01666)\*0.01666)) if Global.backgroundspeed \* 20 \> Global.hispeed then Global.hispeed = Global.backgroundspeed \* 20 end if distancetravelled \> Global.lastdistance then Global.lastdistance = distancetravelled end if Global.backgroundspeed \* 20 \> Global.lastspeed then Global.lastspeed = Global.backgroundspeed \* 20 end if distancetravelled \> Global.bestdistance then Global.bestdistance = distancetravelled end BackgroundObj1.y = BackgroundObj1.y+Global.backgroundspeed BackgroundObj1.contentX, BackgroundObj1.contentY = BackgroundObj1:localToContent(0, 0) BackgroundObj1.Pbuffer = BackgroundObj1.height \* 0.05 BackgroundObj1.P = BackgroundObj1.height \* 0.5 BackgroundObj1.P = BackgroundObj1.P + BackgroundObj1.Pbuffer if BackgroundObj1.contentY \< 0 - BackgroundObj1.P then BackgroundObj1:translate(0, 512) end --move to new position. if displayInfo ~= nil then displayInfo.text = string.format("Speed: %.1f MPH", Global.backgroundspeed \* 20) displayInfo:toFront() end -- check and update scrolling backgrounds if Global.backgroundspeed \> 4 then Global.backgroundspeed = Global.backgroundspeed - 0.0001 end CameraPoint.x = player.x player:toFront( ) -- check scrolling items for i = 1, #ScrollItemsX do ScrollItemsX[i]:translate(ScrollItemsXdist[i], 0) end for i = 1, #ScrollItemsY do ScrollItemsY[i]:translate(0,ScrollItemsYdist[i]) end if Global.controllerdirection == 1 then player.x = player.x - 3 end if Global.controllerdirection == 2 then player.x = player.x + 3 end if player.x \> 288 then player.x = 288 end if player.x \< 8 then player.x = 8 end end Runtime:addEventListener( "enterFrame", on\_enterFrame ) end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:create()" \*\*\*\* END \*\*\*\* -- "scene:show()" function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Called when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Called when the scene is now on screen -- Insert code here to make the scene come alive -- Example: start timers, begin animation, play audio, etc. -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -- GAME CODE HERE ! -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -- This will remove the game scene when available. This is important to allow the game scene to reset itself. local prevScene = composer.getSceneName( "previous" ) if(prevScene) then composer.removeScene( prevScene ) end end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:show() - will / did " \*\*\*\* END \*\*\*\* end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:show()" \*\*\*\* END \*\*\*\* -- "scene:hide()" function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Called when the scene is on screen (but is about to go off screen) -- Insert code here to "pause" the scene -- Example: stop timers, stop animation, stop audio, etc. elseif ( phase == "did" ) then -- Called immediately after scene goes off screen end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:hide() - will / did " \*\*\*\* END \*\*\*\* end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:hide()" \*\*\*\* END \*\*\*\* -- "scene:destroy() function scene:destroy( event ) local sceneGroup = self.view -- \*\*\* JUST ADDED THE BELOW !!! TO TRY AND SEE IF THIS STOPS FPS DROP !! dt = nil last\_ms = nil random = nil camera = nil CameraPoint = nil -- \>\>\> Setup Tables the\_Images = nil the\_Object = nil BackgroundEndless = nil ScrollItemsX = nil ScrollItemsY = nil ScrollItemsXdist = nil ScrollItemsYdist = nil distancetravelled = nil nextcar = nil fingametimer = nil finrect = nil damagebouncespeed = nil damagebounce = nil -- \>\>\> reset GLOBALS Global.backgroundspeed = 3 Global.directionstart = 0 Global.controllerdirection = 0 Global.lastspeed = 0 Global.lastdistance = 0 Global.laneoccupied = nil -- \>\>\> setup TIMERS & transistions camstarttimer = nil othercartimer = nil bouncespeed = nil -- \>\>\> setup FUNCTIONS on\_enterFrame = nil generateothercar = nil onCollision = nil finishgame = nil turnoffdamage = nil fingam = nil -- \>\>\> setup players player = nil othercar = nil -- \>\>\> get the graphic filenames the\_GraphicFileNames = nil -- Called prior to the removal of scenes view -- Insert code here to clean up the scene -- Example: remove display objects, save state, etc. end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:destroy()" \*\*\*\* END \*\*\*\* -- ------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ------------------------------------------------------------------------------- return scene

Here’s a couple of things to think about. Slowdowns generally occur for three reasons:

  1. You’re running low on memory. Perhaps you are creating objects and not inserting them into Composer’s view group such as spawned things that went off screen (so you don’t see them any more and wouldn’t notice it on a screen change). Perhaps you’re loading audio and never disposing of it. You can print out the values of the commands:

print( collectgarbage( “count” ) / 1024 ) – default is to show you Kilobytes of memory, this converts it to Megabytes of memory

print( system.getInfo( “textureMemoryUsed” ) / (1024 * 1024) ) – defaults to bytes, this converts it to Megabytes.

Drop those in your scene:show()'s “did” phase and see if your memory keeps going up and up. If it keeps returning to baseline then you are not leaking memory, but it could also show you’re using too much in general.

  1. You are not stopping things that you started. Timers, Transitions, Runtime “enterFrame” listeners, and even physics do not stop when you transition scenes. You have to stop them manually (and pause physics). If these build up, they start consuming CPU time and your app will slow down.

  2. Doing too much in a given frame. For your app to hit and maintain 60 fps you have to make sure that any work being done can be completed in 1/60th of a second. Loading big images, audio clips and data files can take more than 0.0166 seconds. If you have for or while loops that are doing a lot of calculations that can cause that “frame” to be late.

You dropped a lot of code above (and thank you for formatting it). It’s going to take some time for any community member to digest it, follow the logic and so on.  But in the mean time look at the three main causes of slow downs (in particularly your memory usage) and make sure everything is getting freed up/stopped between scenes.

Keep in mind that the RecyleOnSceneChange just releases the scene’s view (sceneGroup), it does not clear out tables that may be defined in the scene’s main chunk. Doing a composer.removeScene( “scenename” ) with no other parameters either right before you go to the scene  or in the next scene’s did phase is the easiest way to kill a scene. This won’t nuke audio or stop stuff. But its the easiest cleanup of everything else.

Rob

Thanks Rob for the quick reply and good advice.!

  1. regards collectgarbage( “count” ) /  system.getInfo( “textureMemoryUsed” )  - I’m getting about 2.54mb Texture Memory and 0.6mb which climbs to about 1.5mb Memory Usage (from the collectgarbage-count) during the game. These seem to be at a constant rate and always return to the baseline. However the fps still drops over time / after scene change - I get these figures on each game whether it is running at 60 fps or later running at 20 fps after its slowed down.

  2. with timers, transitions, functions - i have started putting these in local variables - so i can nil them later to be sure they are gone, on the assumption if i nil the variable it and its contents (whatever that may be) are gone for good. Listeners i stop them manually and nil out the variable containing the function (to be sure). i’ve never thought about stopping the physics, i imagined if i nil an object anything else attached / related to it (including the physics) just gets destroyed with it.

  3. the first cycle of the game is always fine - everything runs at 60 fps, the game flies with no problems, its only later after the scene change that things start to slow down.

i like the idea of nuking the scene ! sounds just what i need - when i change scene, i just need it (and all the contents created) gone / wiped, to be reload in a fresh next time. although it sounds like this also will not 100% clear everything - but it still may help me. Thanks.

this is no doubt something im not switching off or clearing correctly - its just finding out what.

I have a few more things im unsure of, which may help sort my problems…

with local variables that are being used during a scene, is it better to :-

A.) forward declare them OUTSIDE the function scene:create( event ), like the below…

local composer = require( "composer" ) local scene = composer.newScene() -- \>\>\> forward declare and put variables used for timers, transitions, functions used for the scene OUTSIDE the scene:create local BackgroundObj1 local starttimer local on\_enterFrame local onCollision -- \>\>\> forward declare and put variables used for timers, transitions, functions used for the scene OUTSIDE the scene:create -- scene:create() appears AFTER variables are declared function scene:create( event ) local sceneGroup = self.view BackgroundObj1 = ... blah ... blah 

I assume doing the above the variables created outside the scene:create would need to be manually set to nil somewhere to clear their contents when the scene had finished.

or, is it better (with a view to easily removing them at the end of a scene / when the scene changes) to  …

B.) declare them INSIDE the function scene:create( event ), like the below…

local composer = require( "composer" ) local scene = composer.newScene() -- scene:create() appears BEFORE variables are declared function scene:create( event ) local sceneGroup = self.view -- \>\>\> declare variables used for timers, transitions, functions used for the scene INSIDE the scene:create local BackgroundObj1 = ... blah ... blah local starttimer = ... blah ... blah local on\_enterFrame local onCollision -- \>\>\> declare variables used for timers, transitions, functions used for the scene INSIDE the scene:create 

I assume doing the above, the variables would automatically clear when the scene (which is a function) had finished.?

my other question is…

is there an easy / simple way to list all the things currently running in the memory…? something more detailed than collectgarbage &  system.getInfo.

i have found this (code below) to list tables which it lists the package / runtime / global tables - i think ?.

I was thinking i could take snaphots during the game of whats going on in the background. If i copy the contents into different text files and compare them (using WinMerge - not manually going through it all) after scene changes - it may highlight the problem and point me in the right direction faster. So i can see if there are tables multiplying in the background without my knowledge.

mind you, its a bit heavy going - i was just wondering, is there a simpler / easier way of displaying whats going on in the background ?

function print\_r ( t ) local print\_r\_cache={} local function sub\_print\_r(t,indent) if (print\_r\_cache[tostring(t)]) then print(indent.."\*"..tostring(t)) else print\_r\_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] =\> "..tostring(t).." {") sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] =\> "'..val..'"') else print(indent.."["..pos.."] =\> "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub\_print\_r(t," ") print("}") else sub\_print\_r(t," ") end print() end print\_r(package) print\_r(Runtime) print\_r(\_G)

once again, thanks in advance for any help provided.

Of the two methods above, I tend to do A for things that I need scene wide access to. If it’s only going to be accessed inside of a function and no where else, declare it local inside of the function.

There isn’t a good way to get a list of things in memory. You just need to keep track of it yourself.

Rob

thanks Rob for the advice.

i think i’ve sorted it, it was nothing to do with the scene change.

after spending time putting all my variables, functions, timers, transitions into tables - so I could cycle through them to 100% erase them, i found it was still slowing down.

then i realised i had a module (in separate lua file) that returns the player object, from within this block of code i had also created the player controller using a touch event listener. The controller was created totally separate to the player inside the module - and no reference was returned to the main game code.

So whilst i was clearing the player object in the game code, it looks like wasn’t clearing / removing the controller.

when playing the game multiple times, it must have been creating more and more controllers which slowed the game.

i’ve removed the controller code from the player module and put it in the main game code - and made sure it is cleared / removed.

everything now returns to 60fps when you play the game over.

thanks again for your help.

Here’s a couple of things to think about. Slowdowns generally occur for three reasons:

  1. You’re running low on memory. Perhaps you are creating objects and not inserting them into Composer’s view group such as spawned things that went off screen (so you don’t see them any more and wouldn’t notice it on a screen change). Perhaps you’re loading audio and never disposing of it. You can print out the values of the commands:

print( collectgarbage( “count” ) / 1024 ) – default is to show you Kilobytes of memory, this converts it to Megabytes of memory

print( system.getInfo( “textureMemoryUsed” ) / (1024 * 1024) ) – defaults to bytes, this converts it to Megabytes.

Drop those in your scene:show()'s “did” phase and see if your memory keeps going up and up. If it keeps returning to baseline then you are not leaking memory, but it could also show you’re using too much in general.

  1. You are not stopping things that you started. Timers, Transitions, Runtime “enterFrame” listeners, and even physics do not stop when you transition scenes. You have to stop them manually (and pause physics). If these build up, they start consuming CPU time and your app will slow down.

  2. Doing too much in a given frame. For your app to hit and maintain 60 fps you have to make sure that any work being done can be completed in 1/60th of a second. Loading big images, audio clips and data files can take more than 0.0166 seconds. If you have for or while loops that are doing a lot of calculations that can cause that “frame” to be late.

You dropped a lot of code above (and thank you for formatting it). It’s going to take some time for any community member to digest it, follow the logic and so on.  But in the mean time look at the three main causes of slow downs (in particularly your memory usage) and make sure everything is getting freed up/stopped between scenes.

Keep in mind that the RecyleOnSceneChange just releases the scene’s view (sceneGroup), it does not clear out tables that may be defined in the scene’s main chunk. Doing a composer.removeScene( “scenename” ) with no other parameters either right before you go to the scene  or in the next scene’s did phase is the easiest way to kill a scene. This won’t nuke audio or stop stuff. But its the easiest cleanup of everything else.

Rob

Thanks Rob for the quick reply and good advice.!

  1. regards collectgarbage( “count” ) /  system.getInfo( “textureMemoryUsed” )  - I’m getting about 2.54mb Texture Memory and 0.6mb which climbs to about 1.5mb Memory Usage (from the collectgarbage-count) during the game. These seem to be at a constant rate and always return to the baseline. However the fps still drops over time / after scene change - I get these figures on each game whether it is running at 60 fps or later running at 20 fps after its slowed down.

  2. with timers, transitions, functions - i have started putting these in local variables - so i can nil them later to be sure they are gone, on the assumption if i nil the variable it and its contents (whatever that may be) are gone for good. Listeners i stop them manually and nil out the variable containing the function (to be sure). i’ve never thought about stopping the physics, i imagined if i nil an object anything else attached / related to it (including the physics) just gets destroyed with it.

  3. the first cycle of the game is always fine - everything runs at 60 fps, the game flies with no problems, its only later after the scene change that things start to slow down.

i like the idea of nuking the scene ! sounds just what i need - when i change scene, i just need it (and all the contents created) gone / wiped, to be reload in a fresh next time. although it sounds like this also will not 100% clear everything - but it still may help me. Thanks.

this is no doubt something im not switching off or clearing correctly - its just finding out what.

I have a few more things im unsure of, which may help sort my problems…

with local variables that are being used during a scene, is it better to :-

A.) forward declare them OUTSIDE the function scene:create( event ), like the below…

local composer = require( "composer" ) local scene = composer.newScene() -- \>\>\> forward declare and put variables used for timers, transitions, functions used for the scene OUTSIDE the scene:create local BackgroundObj1 local starttimer local on\_enterFrame local onCollision -- \>\>\> forward declare and put variables used for timers, transitions, functions used for the scene OUTSIDE the scene:create -- scene:create() appears AFTER variables are declared function scene:create( event ) local sceneGroup = self.view BackgroundObj1 = ... blah ... blah 

I assume doing the above the variables created outside the scene:create would need to be manually set to nil somewhere to clear their contents when the scene had finished.

or, is it better (with a view to easily removing them at the end of a scene / when the scene changes) to  …

B.) declare them INSIDE the function scene:create( event ), like the below…

local composer = require( "composer" ) local scene = composer.newScene() -- scene:create() appears BEFORE variables are declared function scene:create( event ) local sceneGroup = self.view -- \>\>\> declare variables used for timers, transitions, functions used for the scene INSIDE the scene:create local BackgroundObj1 = ... blah ... blah local starttimer = ... blah ... blah local on\_enterFrame local onCollision -- \>\>\> declare variables used for timers, transitions, functions used for the scene INSIDE the scene:create 

I assume doing the above, the variables would automatically clear when the scene (which is a function) had finished.?

my other question is…

is there an easy / simple way to list all the things currently running in the memory…? something more detailed than collectgarbage &  system.getInfo.

i have found this (code below) to list tables which it lists the package / runtime / global tables - i think ?.

I was thinking i could take snaphots during the game of whats going on in the background. If i copy the contents into different text files and compare them (using WinMerge - not manually going through it all) after scene changes - it may highlight the problem and point me in the right direction faster. So i can see if there are tables multiplying in the background without my knowledge.

mind you, its a bit heavy going - i was just wondering, is there a simpler / easier way of displaying whats going on in the background ?

function print\_r ( t ) local print\_r\_cache={} local function sub\_print\_r(t,indent) if (print\_r\_cache[tostring(t)]) then print(indent.."\*"..tostring(t)) else print\_r\_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] =\> "..tostring(t).." {") sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] =\> "'..val..'"') else print(indent.."["..pos.."] =\> "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub\_print\_r(t," ") print("}") else sub\_print\_r(t," ") end print() end print\_r(package) print\_r(Runtime) print\_r(\_G)

once again, thanks in advance for any help provided.

Of the two methods above, I tend to do A for things that I need scene wide access to. If it’s only going to be accessed inside of a function and no where else, declare it local inside of the function.

There isn’t a good way to get a list of things in memory. You just need to keep track of it yourself.

Rob

thanks Rob for the advice.

i think i’ve sorted it, it was nothing to do with the scene change.

after spending time putting all my variables, functions, timers, transitions into tables - so I could cycle through them to 100% erase them, i found it was still slowing down.

then i realised i had a module (in separate lua file) that returns the player object, from within this block of code i had also created the player controller using a touch event listener. The controller was created totally separate to the player inside the module - and no reference was returned to the main game code.

So whilst i was clearing the player object in the game code, it looks like wasn’t clearing / removing the controller.

when playing the game multiple times, it must have been creating more and more controllers which slowed the game.

i’ve removed the controller code from the player module and put it in the main game code - and made sure it is cleared / removed.

everything now returns to 60fps when you play the game over.

thanks again for your help.