Memory leaks with sprites

Hello,

I’m working on my first project with Lua / Corona and starting noticing some bad memory leaks now that I’m paying more attention to my memory usage.

With a little bit of troubleshooting, it seems as though the leak is directly related to the amount of characters I have in a scene that are being animated using sprite sheets. For example, an intro “cinematic” that features every character in the game leaks a ton, but a basic stage with minimal sprites doesn’t leak nearly as much. I replaced the sprites with static images and the scene didn’t seem to leak at all.

I’m using Director class to change scenes. Why would Director take care of my static / background images fine but not free up my sprite texture memory? Are extra steps required for unrequireing these sprite sheets?

I’m probably missing something fundamental. I appreciate any help.

-Brandon [import]uid: 136211 topic_id: 31400 reply_id: 331400[/import]

A quick update on this… I followed Danny’s Optimization 101 post on how to organize and remove sprite sheets. Right before Director changes scenes I called the dispose() method that Danny recommended. I got this:

“ERROR: Attempt to remove an object that’s already been removed from the stage or whose parent/ancestor group has already been removed.”

So unless I’m misunderstanding something… Corona isn’t freeing up the texture memory from my sprites if I DON’T manually dispose of them. But if I DO try and manually dispose them, I get an error saying they’ve already been removed.

Does anyone have an idea? I can try to link code if that will help although there’s quite a bit. Thanks,

-Brandon [import]uid: 136211 topic_id: 31400 reply_id: 125514[/import]

Code for loading + destroying/disposing sprites/sheets would be useful here. [import]uid: 52491 topic_id: 31400 reply_id: 125525[/import]

I started by placing my sprite sheets into a table like so…

  
local spriteSheets = {  
 ["character1"] = sprite.newSpriteSheetFromData("sprites/character1sprite.png", require("sprites.character1sprite").getSpriteSheetData()),  
 ["character2"] = sprite.newSpriteSheetFromData("sprites/character2sprite.png", require("sprites.character2sprite").getSpriteSheetData()),  
 ["character3"] = sprite.newSpriteSheetFromData("sprites/character3sprite.png", require("sprites.character3sprite").getSpriteSheetData()),  
 ["little1"] = sprite.newSpriteSheetFromData("sprites/little1sprite.png", require("sprites.little1sprite").getSpriteSheetData()),  
 ["crystal1"] = sprite.newSpriteSheetFromData("sprites/crystal1sprite.png", require("sprites.crystal1sprite").getSpriteSheetData()),  
 ["pincer1"] = sprite.newSpriteSheetFromData("sprites/pincer1sprite.png", require("sprites.pincer1sprite").getSpriteSheetData()),  
 ["pincer2"] = sprite.newSpriteSheetFromData("sprites/pincer2sprite.png", require("sprites.pincer2sprite").getSpriteSheetData()),  
 ["firefly1"] = sprite.newSpriteSheetFromData("sprites/firefly1sprite.png", require("sprites.firefly1sprite").getSpriteSheetData()),  
 ["batbean1"] = sprite.newSpriteSheetFromData("sprites/batbean1sprite.png", require("sprites.batbean1sprite").getSpriteSheetData()),  
 ["octobean1"] = sprite.newSpriteSheetFromData("sprites/octobean1sprite.png", require("sprites.octobean1sprite").getSpriteSheetData()),  
 }  

And I’ll typically call in a character using something like…

  
local function newFirefly()  
  
 local firefly1set = sprite.newSpriteSet(spriteSheets["firefly1"], 1, 4)  
 sprite.add(firefly1set, "buzz", 1, 4, 500, -2 )  
 local firefly = sprite.newSprite(firefly1set)  
 firefly:prepare("buzz")  
 firefly:play()  
 enemylayer:insert(firefly)  
 return firefly  
  
end  
  
local firefly1 = newFirefly()  
firefly1.x = \_W/4  
firefly1.y = \_H/4  
  

Up until today I hadn’t been particularly worried about removing scene objects at the end of each stage because I was assuming (maybe incorrectly) that Director was doing it for me. When I noticed the memory leak I started to look closer and noticed the correlation with the sprites, but it could be display objects in general.

My typical scene changing function goes something like…

  
local function nextStage(event)  
 if(event.phase == "ended" or event.phase == "cancelled") then  
 Runtime:removeEventListener("enterFrame", moveCamera)  
 audio.fadeOut({channel=1, time=500})  
 local function goNext()  
 audio.dispose(soundtrack)  
 soundtrack = nil  
  
 tnt:cancelAllTransitions() -- from Timers and Transitions external module  
 tnt:cancelAllTimers()  
  
 local tRemove = table.remove -- Code from Danny @Ansca Mobile  
   
 for i, v in pairs(spriteSheets) do  
 spriteSheets[i]:dispose()  
 spriteSheets[i] = nil  
 end  
  
 tRemove(spriteSheets) -- End code from Danny  
  
 \_G.stage = "stage"..(currentStage +1) -- Game data stored in global variable  
 director:changeScene("restart", fxMode)  
 end  
 next1.timer = tnt:newTimer(550, goNext, 1)  
 end  
end  
  

I’ve been getting an error since I added the code Danny recommended but the memory leak was occurring without it. I’m also open to any general feedback regarding ways to approach this differently if you noticing any other quirks or problems. As stated before, this is my first go with Corona :slight_smile:

Thanks again [import]uid: 136211 topic_id: 31400 reply_id: 125533[/import]

Hello all, I know this is a lot to read thru at this point but I still haven’t been able to resolve the issue and would appreciate any tips if anything here jumps out at anyone. Thanks.

-Brandon [import]uid: 136211 topic_id: 31400 reply_id: 125603[/import]

It may also be worth noting that one of the errors related to this issue is tracing back to the tnt module (http://developer.coronalabs.com/code/pausable-timers-and-transitions-speed-adjustment) so I wonder if it’s a part of the problem or if one of the objects causing the error is simply using a timer / transition from tnt.

I’d love to know if anyone else has experienced anything like this… memory leaks associated either with sprite sheets or the tnt module? [import]uid: 136211 topic_id: 31400 reply_id: 125667[/import]

A quick update on this… I followed Danny’s Optimization 101 post on how to organize and remove sprite sheets. Right before Director changes scenes I called the dispose() method that Danny recommended. I got this:

“ERROR: Attempt to remove an object that’s already been removed from the stage or whose parent/ancestor group has already been removed.”

So unless I’m misunderstanding something… Corona isn’t freeing up the texture memory from my sprites if I DON’T manually dispose of them. But if I DO try and manually dispose them, I get an error saying they’ve already been removed.

Does anyone have an idea? I can try to link code if that will help although there’s quite a bit. Thanks,

-Brandon [import]uid: 136211 topic_id: 31400 reply_id: 125514[/import]

Code for loading + destroying/disposing sprites/sheets would be useful here. [import]uid: 52491 topic_id: 31400 reply_id: 125525[/import]

I started by placing my sprite sheets into a table like so…

  
local spriteSheets = {  
 ["character1"] = sprite.newSpriteSheetFromData("sprites/character1sprite.png", require("sprites.character1sprite").getSpriteSheetData()),  
 ["character2"] = sprite.newSpriteSheetFromData("sprites/character2sprite.png", require("sprites.character2sprite").getSpriteSheetData()),  
 ["character3"] = sprite.newSpriteSheetFromData("sprites/character3sprite.png", require("sprites.character3sprite").getSpriteSheetData()),  
 ["little1"] = sprite.newSpriteSheetFromData("sprites/little1sprite.png", require("sprites.little1sprite").getSpriteSheetData()),  
 ["crystal1"] = sprite.newSpriteSheetFromData("sprites/crystal1sprite.png", require("sprites.crystal1sprite").getSpriteSheetData()),  
 ["pincer1"] = sprite.newSpriteSheetFromData("sprites/pincer1sprite.png", require("sprites.pincer1sprite").getSpriteSheetData()),  
 ["pincer2"] = sprite.newSpriteSheetFromData("sprites/pincer2sprite.png", require("sprites.pincer2sprite").getSpriteSheetData()),  
 ["firefly1"] = sprite.newSpriteSheetFromData("sprites/firefly1sprite.png", require("sprites.firefly1sprite").getSpriteSheetData()),  
 ["batbean1"] = sprite.newSpriteSheetFromData("sprites/batbean1sprite.png", require("sprites.batbean1sprite").getSpriteSheetData()),  
 ["octobean1"] = sprite.newSpriteSheetFromData("sprites/octobean1sprite.png", require("sprites.octobean1sprite").getSpriteSheetData()),  
 }  

And I’ll typically call in a character using something like…

  
local function newFirefly()  
  
 local firefly1set = sprite.newSpriteSet(spriteSheets["firefly1"], 1, 4)  
 sprite.add(firefly1set, "buzz", 1, 4, 500, -2 )  
 local firefly = sprite.newSprite(firefly1set)  
 firefly:prepare("buzz")  
 firefly:play()  
 enemylayer:insert(firefly)  
 return firefly  
  
end  
  
local firefly1 = newFirefly()  
firefly1.x = \_W/4  
firefly1.y = \_H/4  
  

Up until today I hadn’t been particularly worried about removing scene objects at the end of each stage because I was assuming (maybe incorrectly) that Director was doing it for me. When I noticed the memory leak I started to look closer and noticed the correlation with the sprites, but it could be display objects in general.

My typical scene changing function goes something like…

  
local function nextStage(event)  
 if(event.phase == "ended" or event.phase == "cancelled") then  
 Runtime:removeEventListener("enterFrame", moveCamera)  
 audio.fadeOut({channel=1, time=500})  
 local function goNext()  
 audio.dispose(soundtrack)  
 soundtrack = nil  
  
 tnt:cancelAllTransitions() -- from Timers and Transitions external module  
 tnt:cancelAllTimers()  
  
 local tRemove = table.remove -- Code from Danny @Ansca Mobile  
   
 for i, v in pairs(spriteSheets) do  
 spriteSheets[i]:dispose()  
 spriteSheets[i] = nil  
 end  
  
 tRemove(spriteSheets) -- End code from Danny  
  
 \_G.stage = "stage"..(currentStage +1) -- Game data stored in global variable  
 director:changeScene("restart", fxMode)  
 end  
 next1.timer = tnt:newTimer(550, goNext, 1)  
 end  
end  
  

I’ve been getting an error since I added the code Danny recommended but the memory leak was occurring without it. I’m also open to any general feedback regarding ways to approach this differently if you noticing any other quirks or problems. As stated before, this is my first go with Corona :slight_smile:

Thanks again [import]uid: 136211 topic_id: 31400 reply_id: 125533[/import]

Hello all, I know this is a lot to read thru at this point but I still haven’t been able to resolve the issue and would appreciate any tips if anything here jumps out at anyone. Thanks.

-Brandon [import]uid: 136211 topic_id: 31400 reply_id: 125603[/import]

It may also be worth noting that one of the errors related to this issue is tracing back to the tnt module (http://developer.coronalabs.com/code/pausable-timers-and-transitions-speed-adjustment) so I wonder if it’s a part of the problem or if one of the objects causing the error is simply using a timer / transition from tnt.

I’d love to know if anyone else has experienced anything like this… memory leaks associated either with sprite sheets or the tnt module? [import]uid: 136211 topic_id: 31400 reply_id: 125667[/import]

Are you still having the leak when not using that library? [import]uid: 52491 topic_id: 31400 reply_id: 126120[/import]

Well, it turns out the increase in texture memory was indeed an issue with Lua not releasing sprite sheets upon scene change. I’ve managed to get the issue somewhat resolved by removing them manually.

And there was an issue with the tnt module. There was a “cleanTimersAndTransitions()” function I wasn’t calling enough and I believe that was causing my memUsage to rise higher than it should have (particularly with my custom particle effects).

I’m still having a curious leak changing between scenes, however. I’ve noticed memUsage is 50+kb higher when I re-enter a scene compared to when I initially entered it. But here’s the interesting part… the “leak” only occurs once. After, I can go back and forth between two scenes seemingly indefinitely without any additional memory increases. This might be a an issue I’ll take up in the Director forums.

Thanks for following up on this,

Brandon [import]uid: 136211 topic_id: 31400 reply_id: 126144[/import]

Are you still having the leak when not using that library? [import]uid: 52491 topic_id: 31400 reply_id: 126120[/import]

Well, it turns out the increase in texture memory was indeed an issue with Lua not releasing sprite sheets upon scene change. I’ve managed to get the issue somewhat resolved by removing them manually.

And there was an issue with the tnt module. There was a “cleanTimersAndTransitions()” function I wasn’t calling enough and I believe that was causing my memUsage to rise higher than it should have (particularly with my custom particle effects).

I’m still having a curious leak changing between scenes, however. I’ve noticed memUsage is 50+kb higher when I re-enter a scene compared to when I initially entered it. But here’s the interesting part… the “leak” only occurs once. After, I can go back and forth between two scenes seemingly indefinitely without any additional memory increases. This might be a an issue I’ll take up in the Director forums.

Thanks for following up on this,

Brandon [import]uid: 136211 topic_id: 31400 reply_id: 126144[/import]