problem with Garbage Collection for a spritesheet

Hello there,

I’m having big issues with a memory leak. I know where the leak is, but can’t seem to fix it.

my ‘currentAnimation’ is created with a function:

self.currentAnimation = Factory.NewSpriteSequence(
animationName,
{ name=animationName, start=1, time=1200, loopCount=1 },
true )

the function looks like this:

function NewSpriteSequence( sheetName, seqParams )
   
   local sheetInfo = require (‘mejn.sprite.’…sheetName)
   local sheet = graphics.newImageSheet(‘images/sprites/’…sheetName…’.png’,sheetInfo:getSheet())
   seqParams.count = seqParams.count or #sheetInfo:getSheet().frames
   seqParams.start = 1 or seqParams.start
   local sprite = display.newSprite( sheet, seqParams )
   sprite.name = sheetName
   sprite.sheet = sheet
   return sprite
end
and then later I clean it with this snippet:

if self.currentAnimation then
       TransitionManager:killTweensOf( self.currentAnimation )
       self.currentAnimation:removeEventListener( “sprite”, self )    
       self.currentAnimation:removeSelf()
       self.currentAnimation.sheet = nil
       self.currentAnimation = nil
end

but somehow it wont get garbage collected and my memory usage keeps growing…

I tried a lot but can’t seem to find what I’m doing wrong, any suggestions would be highly appreciated,

Thanks,

Wouter

[import]uid: 133360 topic_id: 27837 reply_id: 327837[/import]

Are you disposing of the sheet?
http://developer.anscamobile.com/reference/index/spritesheetdispose [import]uid: 52491 topic_id: 27837 reply_id: 112751[/import]

hello Peach,

Thank you for your reply.

But it’s not the old sprite api I’m dealing with, it’s imageSheet which does not expose the dispose method…

Wouter [import]uid: 133360 topic_id: 27837 reply_id: 112760[/import]

D’oh - sorry about that. I’ve just sent an email to another member of the team to see if they have any advice on this; I haven’t done much with the new sprite stuff yet but should be able to get some valuable insight for you from him. Hang tight! [import]uid: 52491 topic_id: 27837 reply_id: 112858[/import]

Hanging in there…barely…need…help…

much appreciated, hope to get some useful advice, I still couldn’t solve it myself!

Wouter [import]uid: 133360 topic_id: 27837 reply_id: 112861[/import]

I just did a simple test case (below) and didn’t see a memory leak. I think your problem is that in your NewSpriteSequence() function, you add ‘sheet’ as a property of ‘sprite’. Late on, even though you call removeSelf(), the ‘sprite’ still has a property that’s referencing ‘sheet’ (removeSelf() only removes all the DisplayObject stuff, so what’s left is a plain Lua table, including any properties you set on that table).

It’s best to avoid having the sprite hold onto a reference to the sheet, i.e. remove the line ‘sprite.sheet = sheet’, so you don’t have to remember to ‘nil’-out the reference later.

If you must add a reference, then you’ll need to remember to ‘nil’ the reference out later, i.e. nil-out the sheet property of sprite after you call removeSelf on it: ‘sprite.sheet = nil’

Anyway, here’s my test case using daily build 840. I create an image sheet, then a sprite. Then I remove it, and nil-out the local var ‘sheet’. I print out the amount of texture memory used 3 times after forcing a GC. Notice it goes to 0 at the end.

[code]
local options =
{
– Required params
width = 64,
height = 64,
numFrames = 256,

– content scaling
sheetContentWidth = 1024,
sheetContentHeight = 1024,
}
local sheet = graphics.newImageSheet( “dancers.png”, options )

local start = 1
local numFrames = 16
local seq = { name=dancer, start=start, count=numFrames, loopCount=2 }

local s = display.newSprite( sheet, seq )

– (1) Expected memory due to image sheet
print( system.getInfo( “textureMemoryUsed” ) ) --> 4194304

– (2) Image sheet is still around b/c of outstanding ‘sheet’ reference
s:removeSelf()
collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 4194304

– (3) Remove all references to the image sheet
sheet = nil
collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 0
[/code] [import]uid: 26 topic_id: 27837 reply_id: 112986[/import]

I was having issue with the same thing. I took the code example here provided by Walter which does just what it says it does.

BUT, I modified it a little to stream it down and to fit the issue I am having, and discovered a slight issue with it.

When assigning a touch listener to the ‘image object’ created from an imagesheet the texture memory does not get released!!!

When the listener touch event is triggered in my sample code here, in the function I remove the listener, remove the image object correctly and ‘nil’ the image object. And then ‘nil’ the imagesheet … MEMORY CONSUMED BY THE IMAGE SHEET DOES NOT CLEAR.
HOWEVER, if I run the same exact code, but make the touch listener on Runtime, and have that touch event remove the image object, and the all the same object clean up stuff I do when it is attached to the image object, it DOES indeed clear the texture memory.
The issue is this: when an event listener is attached to a display object that was created from an imagesheet, even after proper steps to remove and nil that object, the imagesheet when nil’d does not release the texture memory!

The question is: is there another step to follow in cases where the image object(created from an imagesheet) has an event listener attached ???
OR is this a bug with the imagesheet?
I have both examples of the code I tested here :

  1. with event listener on the image object (does not release memory)

local options = { width = 100, height = 100, numFrames = 9, sheetContentWidth = 300, sheetContentHeight = 300}

local sheet = graphics.newImageSheet( “numSheet300.png”, options )

local s = display.newImage( sheet, 1 )
s.x = 100
s.y = 100
print( system.getInfo( “textureMemoryUsed” ) )

local function clearIt(e)
if e.phase == “ended” then
s:removeEventListener(“touch”, clearIt)
s:removeSelf()
s = nil

collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576

sheet = nil
collectgarbage( “collect” ) --> STILL 1048576
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576
end
end

s:addEventListener(“touch”, clearIt)

  1. event listener on Runtime (does release the memory)

local options = { width = 100, height = 100, numFrames = 9, sheetContentWidth = 300, sheetContentHeight = 300}
local sheet = graphics.newImageSheet( “numSheet300.png”, options )

local s = display.newImage( sheet, 1 )
s.x = 100
s.y = 100
print( system.getInfo( “textureMemoryUsed” ) )

local function clearIt(e)
if e.phase == “ended” then
Runtime:removeEventListener(“touch”, clearIt)
s:removeSelf()
s = nil

collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576

sheet = nil
collectgarbage( “collect” ) --> CLEARS THE MEMORY
print( system.getInfo( “textureMemoryUsed” ) ) --> 0
end
end

Runtime:addEventListener(“touch”, clearIt)
I really like the ImageSheet … it is a great tool and does some very good things, and I have it at the core of what my app is doing, so I need to find a way to fix this memory leak.

Thanks!
[import]uid: 148857 topic_id: 27837 reply_id: 140858[/import]

@cyberparkstudios, when you remove an object that’s _underneath_ a touch, and then attempt to remove it in a touch listener, Corona does not release associated resources right away because that object is in a list of potential objects that can be dispatched the touch listener. Sometime later, the object’s resources are released.

You can see that by adding an enterFrame listener like the following:

local i = 0  
Runtime:addEventListener( "enterFrame", function( event )  
 -- display roughly every second  
 i = i + 1  
 if ( i \> 30 ) then  
 i = 0  
 collectgarbage( "collect" ) --\> STILL 1048576  
 print( system.getInfo( "textureMemoryUsed" ) ) --\> 1048576  
 end  
end)  

[import]uid: 26 topic_id: 27837 reply_id: 140908[/import]

Thank you Walter. That works.
[RESOLVED] [import]uid: 148857 topic_id: 27837 reply_id: 140916[/import]

I was having issue with the same thing. I took the code example here provided by Walter which does just what it says it does.

BUT, I modified it a little to stream it down and to fit the issue I am having, and discovered a slight issue with it.

When assigning a touch listener to the ‘image object’ created from an imagesheet the texture memory does not get released!!!

When the listener touch event is triggered in my sample code here, in the function I remove the listener, remove the image object correctly and ‘nil’ the image object. And then ‘nil’ the imagesheet … MEMORY CONSUMED BY THE IMAGE SHEET DOES NOT CLEAR.
HOWEVER, if I run the same exact code, but make the touch listener on Runtime, and have that touch event remove the image object, and the all the same object clean up stuff I do when it is attached to the image object, it DOES indeed clear the texture memory.
The issue is this: when an event listener is attached to a display object that was created from an imagesheet, even after proper steps to remove and nil that object, the imagesheet when nil’d does not release the texture memory!

The question is: is there another step to follow in cases where the image object(created from an imagesheet) has an event listener attached ???
OR is this a bug with the imagesheet?
I have both examples of the code I tested here :

  1. with event listener on the image object (does not release memory)

local options = { width = 100, height = 100, numFrames = 9, sheetContentWidth = 300, sheetContentHeight = 300}

local sheet = graphics.newImageSheet( “numSheet300.png”, options )

local s = display.newImage( sheet, 1 )
s.x = 100
s.y = 100
print( system.getInfo( “textureMemoryUsed” ) )

local function clearIt(e)
if e.phase == “ended” then
s:removeEventListener(“touch”, clearIt)
s:removeSelf()
s = nil

collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576

sheet = nil
collectgarbage( “collect” ) --> STILL 1048576
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576
end
end

s:addEventListener(“touch”, clearIt)

  1. event listener on Runtime (does release the memory)

local options = { width = 100, height = 100, numFrames = 9, sheetContentWidth = 300, sheetContentHeight = 300}
local sheet = graphics.newImageSheet( “numSheet300.png”, options )

local s = display.newImage( sheet, 1 )
s.x = 100
s.y = 100
print( system.getInfo( “textureMemoryUsed” ) )

local function clearIt(e)
if e.phase == “ended” then
Runtime:removeEventListener(“touch”, clearIt)
s:removeSelf()
s = nil

collectgarbage( “collect” )
print( system.getInfo( “textureMemoryUsed” ) ) --> 1048576

sheet = nil
collectgarbage( “collect” ) --> CLEARS THE MEMORY
print( system.getInfo( “textureMemoryUsed” ) ) --> 0
end
end

Runtime:addEventListener(“touch”, clearIt)
I really like the ImageSheet … it is a great tool and does some very good things, and I have it at the core of what my app is doing, so I need to find a way to fix this memory leak.

Thanks!
[import]uid: 148857 topic_id: 27837 reply_id: 140858[/import]

@cyberparkstudios, when you remove an object that’s _underneath_ a touch, and then attempt to remove it in a touch listener, Corona does not release associated resources right away because that object is in a list of potential objects that can be dispatched the touch listener. Sometime later, the object’s resources are released.

You can see that by adding an enterFrame listener like the following:

local i = 0  
Runtime:addEventListener( "enterFrame", function( event )  
 -- display roughly every second  
 i = i + 1  
 if ( i \> 30 ) then  
 i = 0  
 collectgarbage( "collect" ) --\> STILL 1048576  
 print( system.getInfo( "textureMemoryUsed" ) ) --\> 1048576  
 end  
end)  

[import]uid: 26 topic_id: 27837 reply_id: 140908[/import]

Thank you Walter. That works.
[RESOLVED] [import]uid: 148857 topic_id: 27837 reply_id: 140916[/import]