Do Director Class Set Nil To All The Objects From Last Scene?

For the life of me, I couldn’t understand why my new game started crashing all over the place.  Thought it was a Daily Build (even went back to 971 and it crashed a lot less, but eventually did), but when I saw WilerJr’s post, I got desperate and changed all my display.remove( object ) functions with if object.removeSelf then object:removeSelf() end.

Needless to say, it stopped crashing (I even let my iPad run my app and my MacBook Air run my app in the Simulator all night), but Tom at Corona says that section of code hasn’t been changed in a long time.

Go figure. At least I can continue to move forward with development. This one was a show-stopper!

Nothing has changed with display.remove. Here is the internal code and you can see that it checks for a nil object and then verifies that the object has the removeSelf method attached.

-- convenience wrapper for object:removeSelf() that eliminates check for a receiver that's nil display.remove = function( object ) if object then local method = object.removeSelf if "function" == type( method ) then method( object ) -- same as object:removeSelf() end end end
function removeOffscreenItems()         for i = #images, 1, -1 do             local oneImage = images[i]             if(oneImage.alpha == 0 or removeOffscreenItemsController == true)then                 oneImage:removeSelf();                 table.remove( images, i ) ;              end             end end  

This is where I remove the images created by 

background:addEventListener("touch", creator);  

removeOffscreenItemsController is a control variable to verify if the freeEverything function is running and clean the images when its listener to alpha is already removed. At the end of freeEverything, I call a timer that changes the screen after 500~1000 miliseconds.

This is my creator function:

function creator(e)             if(e.phase == "began")then                  images[#images + 1] = display.newImage(........)                  image = images[#images];                  transition.to(image, {alpha = 0});                  localGroup:insert(image);             end end  

I think the problem is the transition, but I can’t cancel it… is there a way to link a image to a specific transition so I can remove it?

Edit: I created a transitions table and I’m trying to make it work… :stuck_out_tongue:

http://docs.coronalabs.com/api/library/transition/to.html

“This function returns a tween reference corresponding to the animation (or interpolation) of the object target based on property values specified in params.”

In other words, you want to be able to reference the transition action in the likely event that you need to cancel it.

Try simplifying the function to this:

function creator(e) if(e.phase == "began")then local newimageindex = #images + 1 images[newimageindex] = display.newImage(........) images[newimageindex].trans = transition.to(images[newimageindex], {alpha = 0}); localGroup:insert( images[newimageindex] ); end end

Now, the transition is captured in a property variable called trans.  At any point - whether the transition is in progress, or even if the transition is over - that trans variable still exists under that particular image.  So, you can then sweep through the entire roster of images and cancel them out:

for i = 1, #images do if images[i].trans then transition.cancel( images[i].trans ) end end

You can do it for timers as well, just place as a property of the image itself:

images[newimageindex].timer = timer.performWithDelay( 100, doSomeArtificialIntelligence ) ... if images[i].timer then timer.cancel( images[i].timer ) end

I’m using this object[newObjectIndex].trans you taught, but didn’t solve the problem.

It’s becoming even harder to deal with that issue… ;s

Take the example: I go into a screen, then use creator function to create images, right? In that time, let’s supose, the memory usage is 316. I create images and the memory usage grows. So the images are transition’ed to alpha = 0 and the removeOffscreenItems works, turning down the memory usage, but… it does not come back to 316; it comes back to a number like 339.

And a incredible thing: the table.getn(images) shows a value 0 when printed after the work of removeOffscreenItems.

If I create a huge quantity of images then go back to menu, the memory usage shows a value like 400; if I create nothing then go back to menu, the memory usage show a value like 350! What’s wrong here if I’m removing all the objects (by localGroup:removeSelf()) and all the listeners?

I think I’m about to fix that problem, but I need to know what’s missing… 

Hey! Don’t forget this topic!

Unfortunately, until there’s a new kid on the block, for both Director and Storyboard, you’re responsible for making sure all display objects, timers, and transitions are properly removed, canceled, and nil’ed before exiting a scene.

I would suggest tying all timers and transitions to the object you’re working with, like this:

object.timer = timer.performWithDelay( 1000, moveObjectFunction, 0 ) object.trans = transition.to( object, { time = 500, alpha = 0, onComplete = function() resetAlpha( object ) end } ) ... timer.cancel( object.timer ) transition.cancel( object.trans ) display.remove( object ) object = nil

Maybe that’s it, because I don’t set nil to all my objects.

Is there a large difference between 

display.remove(object)  

 and 

object:removeSelf()  

?

What if I use the following?

localGroup:removeSelf(); localGroup = nil;  

The localGroup contains all my objects.

removeSelf brings back some bad memories for me.  When I used to use it, I had to perform a check, or Corona would crash:

if object and object.removeSelf then object:removeSelf() object = nil end

Now, I just use this:

display.remove( object ) object = nil

Works regardless if it was a displayObject or if it was partially deleted (or is being concurrently deleted) by another function.  I believe you could do localGroup:removeSelf(), but I believe there is also unloadScene and localGroup:clean() in Director as well.  Best to experiment and see if the memory is getting cleared by performing a memory check before and after you do your cleanup routines:

print( string.format( "%.3f", system.getInfo( "textureMemoryUsed" ) / 1000000 ) .. "MB texture memory allocated" )

I have no problem with removeSelf, Raphael. It’s strange. I’ll try setting nil to all of my objects and see if it solves the problem. If not, I come back here and tell you.

function removeOffscreenItems()           for i = 1,#images do local oneImage = images[i]             if (oneImage and oneImage.alpha)then                 if(oneImage.alpha == 0)then                     oneImage:removeSelf();                     oneImage = nil;                     table.remove( images, i);                   end                 end         end end  

Is there a possibility where that function is not deleting all the images of the table when I tap to exit from a scene? When I choose to close the scene, I remove the enterFrame listener of that function. Maybe it’s not having to delete all the images, do you think the same?

http://www.coronalabs.com/blog/2011/08/15/corona-sdk-memory-leak-prevention-101/#comment-864

Nice post that one!

The problem is almost solved, because I still need to know if the function I posted above is deleting all the images before I change the screen I’m in.

Hi @WilerJr,
 
Just a note, if your “images” table stores typical images… and I assume it does… you need to loop backwards through it as you clear it out. Why? If you go forward as you typed above, you’ll only clear every other instance out. It works on this logic.
 
[lua]
–sample table (numbers in place of images, but same idea).
{1,2,3,4,5,6}
–we’ll assume you’re looping from 1 to #images (6).
–iterator “i” is 1… clear that table entry:
{2,3,4,5,6}
–iterator “i” is now 2, clear it… but it hits value “3”, not “2” as you might expect
{2,4,5,6}
–iterator “i” is now 3 (value “5” is cleared)
{2,4,6}
–loop terminates
[/lua]
 
As you can see, you’re left with half of your images still in there. Bad news if you want to clear all images from a table so Lua can garbage-collect them!
 
The solution is to just iterate backwards through the loop.
 
[lua]
for i=#images,1,-1 do
–clear images[i]
end
[/lua]
 
Hope this helps; it’s a fairly common misunderstanding.
 
Brent

Wow! Living then learning. :stuck_out_tongue: It breaks the logic I’ve learned before starting with Corona! haha Thank you once more, Brent.

And tell me one thing: do I have to free local variables before exiting a screen?

My question comes up because even changing the removeOffScreenItems function to your way, nil’ing the objects and removing all runtime and objects listeners, when I go out the screen, the memory usage goes growing every past screen… then I get some lag after a time switching scenes…

Note: before creating a function I call 

local functionName = {};  

on top of my code and when I’m closing a screen I don’t nil it. Is this wrong?

Hi @WilerJr,

You don’t need to nil out local variables on scene change, assuming you don’t reference them somewhere else (in another containing table), attach a Runtime listener to them, or something else that might be locking them in memory. If you isolate them before leaving the scene, they should be garbage collected properly.

When you exit the scene, you should check that your “images” table has 0 children (just check “#images”).

I’m afraid your memory leak is somewhere else, and finding it could be like finding a needle in a haystack, unfortunately. :frowning:

Brent

Checking “#images” is not returning a value, Brent… How can I check it?

Tell me a thing, Brent: do all objects inserted on a group be nil’ed if I set nil to this group?

(Editing post) The following code is where I clean my transition, timer and localGroup variables and remove the listeners. This function is called by a “onRelease” inside widget.newButton. Every scene has a function like this.

The function creator creates the images that have to be deleted by removeOffscreenItems function.

function freeEverything()         removeOffscreenItemsController = true;         if(moveTransition)then             transition.cancel(moveTransition);             moveTransition = nil;         end         timer.cancel(counterTimer);         counterTimer = nil;         Runtime:removeEventListener("enterFrame", removeOffscreenItems);         background:addEventListener("touch", creator);         Runtime:removeEventListener("enterFrame", rotate);         audio.stop();         audio.dispose(song);         song = nil;         audio.reserveChannels(0);         physics.stop();         physics = nil;         display.remove(localGroup);         localGroup = nil;         director:changeScene("main\_page", "overFromLeft");         return true;     end  

Does count = table.getn( images ) (getn may be deprecated in Lua 5.1+) or count = images.numChildren give you the proper values?

**count = table.getn( images ) **worked. :smiley: And well… it seems removeOffscreenImages is not removing all the images before closing the screen.

I think I shall create a method to delay a time until that function has cleared all memory. What do you think? 

I use a 500ms timer after killing off all my objects and changing scene, seems to be enough for both Simulator and device.