Do I have to worry anymore about all the listeners and class instances added to a movie clip that is no longer displayed on the scene?
I'm asking because I want to know if it makes sense to clean up after I'm done with a movie clip's instances on the scene.
Yes, you need to clean up.
Event listeners will keep the clip from being garbage collected if they are not removed.
Alternately, you can use weak event listeners. Then the listener will not prevent garbage collection as long as all other references to the clip are removed.
AS3: Weakly Referenced Listeners
Realistically it depends on your app/swf file.
If your app is complicated/extensive and will be used for a lengthy session time wise then yes, you should be manually removing all references, stopping animations and nulling the instances.
Remember that even when the instance is off stage or removed from the display list, it still uses CPU and memory resources.
It is good working practice to do this but not really essential for smaller projects.
Related
Had some issues using the loader and I feel I need to totally understand how the unloadAndStop() method works. I'm working on a project that loads in multiple swfs when required at runtime. For this I've been using a single loader and pulling out its contents to a cache when it's complete.
The single loader is implemented via an extended class that I haven't written, and it seems to implement the "unloadAndStop(true) method when loading in a new URLRequest.
Now, I've had some strange issues using this system, and I've traced it back to the unloadAndStop(true) call, which according to the Adobe documentation stops audio, playback, and flags for removal by the garbage collector. Obviously this isn't what I want; I still have references to this object on the stage and in my cache! It seems strange to me that there's a way to flag something directly for garbage collection in this manner, where, as far as I know, there's no other way to do that.
So that causes me to assume that in order to properly remove something loaded with a loader you have to unload it in the manner. Is this the case? If I load something in, pull out its contents to movieClip1, load in a new movieClip, and then remove all references to movieClip1 (the original Loader contents) will that be garbage collected, or does it have to be removed via the unloadAndStop method?
TL;DR:
Is it necessary to call unloadAndStop(true) from a loader to guarentee anything it has loaded gets removed from memory, or can the loader load another URLRequest without fear of a memory leak?
It's well described in the docs:
gc:Boolean (default = true) — Provides a hint to the garbage collector to run on the child SWF objects (true) or not (false). If you are unloading many objects asynchronously, setting the gc paramter to false might improve application performance. However, if the parameter is set to false, media and display objects of the child SWF file might persist in memory after running the unloadAndStop() command.
It's because you can have some SWF, get some specific child, and remove the SWF. But you keep reference to it's child, which means that the child won't be garbage collected. But if you force GC to check children, it will try to mark all of them for collection, and leave the ones that are used.
So basically, there is no need to force GC in order to clean things out. The best and most important practice is to remove everything from Stage, and clean all references to it. It will sooner or later going to be checked by GC. unloadAndStop is a shortcut for someone that doesn't keep track on what he's doing and just a safety measure to be sure that you've cleaned as much as you can.
I personally don't use it.
I know that event listeners and references to an object will prevent the garbage collector from dealing with objects. My question is, will an event listener placed on an object, listening to the same object, prevent that object from being garbage collected?
I ask because it seems like this is happening to me. I am breaking all my references to an object but I am still seeing traces when its timer goes off. At the same time, it seems like this should not prevent the collection because it would create allocated but unreferenceable memory.
No, but.
The AVM2 garbage collector is supposed to find unreachable objects. But because garbage collection is non-deterministic, it's very hard to rely on or even test this behaviour -- it could be that the garbage collector is working perfectly, but not bothering to run the mark-and-sweep since you have enough RAM free.
It's a good idea to remove event listeners when you're done with the object, even if they're from the object itself (i.e. circular references). Why is this a good idea? Because you never know when the garbage collector is going to run. If you want deterministic behaviour, always remove listeners in a deterministic fashion, especially for time-sensitive events like TIMER and ENTER_FRAME, otherwise you're creating a race condition between your listeners running and the garbage collector running. The garbage collector only runs periodically.
In general, if you want to attach event listeners without creating an additional reference to the object, pass true to the useWeakReference parameter of addEventListener(). If you want to stop receiving the events right away, though, you'll still need to manually detach your event listeners as soon as you're done with the object.
Yes, this will stop the GC from cleaning up your object. A hacky way to try to prevent this is to use weak references when adding listeners.
myobj.addEventListener(Event.EVENT, eventHandler, false, 0, true);
The last true flag will set the listener to use a weak object reference.
Best practice would be to keep track and always remove any active listeners before nulling your object.
Check out this great blog post for more info on this topic
http://gskinner.com/blog/archives/2006/06/as3_resource_ma.html
I have a question how can I clear/free memory in flash? For example I am finishing game and I want to start from beginning and if I will just jump to the first frame all the objects there are still in this memory, is any possibility to force cleaning memory?
Can I free memory for an object? for example I removeChild(something) - and I want to free memory for an object as I will reuse it?
Can anybody explain me how the engine works?
Thanks
I would encourage you to read Chapter 14, Garbage Collection in the "Moock Book" (Essential ActionScript 3.0 by O'Reilly Publishing).
The short answer to your question is that you're not in control of de-allocation, the garbage collector is. In a garbage-collected language like AS3 or Java, you don't have manual control over allocation and de-allocation of memory like you do in lower level languages; there are no AS3 equivalents to things like delete in C++ or free in C. Your goal should not be controlling when you destroy things, but rather not forgetting to remove references to things you no longer need around and making sure you disable things that you intend for garbage collection.
Memory leaks in AS3 typically come from a mixture of newbie misunderstanding (like thinking removeChild or setting a reference to null destroys objects), and from not keeping good track of references to objects--especially where strong listeners are involved.
A previous respondent posted this:
myObject = null;
What this does is remove a reference to the object that the variable myObject was holding. Nothing more. You need to know a lot more about the situation in order to be able to say whether this assignment even makes the object in question eligible for garbage collection, especially how many other variable are holding references to the object. And the object might already be eligible for garbage collection even if you didn't set the reference to null (i.e. if myObject has no connection to a GC root).
Suffice to say, the entire GC mechanism is more complex than can be satisfactorily explained in a StackOverflow post. That's why it has a whole chapter in the Moock Book, and even that book does not go into implemenation detail or great detail about when exactly the Flash Player does its ref counting deletions or mark and sweep passes.
The most important things to remember are, IMHO:
When you intend to "kill" an object, give it a cleanUp() or destroy() function where you do things like stop all its timers, sounds, remove listeners, etc. An object will continue to exist and execute code until it gets GC'd. And the Flash Player defers GC as long as it can--it's usually triggered when the Player needs to allocate more RAM from your system, because allocating memory is about the only thing that's more time consuming than doing the mark and sweep GC pass.
Read about weak vs strong listeners. Basically, when you have a weak listener, the listener reference is one that is ignored by mark-and-sweep GC, so it alone will not prevent an object from getting collected. But don't listen to anyone who tells you "always use weak" or "always use strong listeners and manually remove them" because there are times where each is appropriate, and that's why the choice is yours.
removeChild() will remove object from stage, but will still keep it in memory. You will have to null the object like this myObject = null if you wish to get rid of it entirely. You might not need to do that thought. Just removing it from stage and removing all associated events will be sufficient in most cases.
Clearing memory is a tricky thing with Flash, the proper way ow implementing it setting up objects properly in the first play for easy clearing, rather than forcing deletion. When you want to remove an object from memory, you do it by removing any reference to it, and then flash marks it for garbage collection. Then Flash at a later point removes the object from memory.
In order for the object to be ready for data collection it cannot have any connection to another object.
so if you have an object that has a single connection to a MovieClip and the movie clip has no other relation, then if you set it to null, you will remove it.
if you, however, have two objects that point to it, if you remove one link by setting it to null, the MovieClip will not be removed.
furhtermore, if you have a 2 or more movie clips that have a network of connections, removing those objects requires these connections be broken as-well. For example if you have a level with many characters and listeners set up, removing the lavel movieClip will not clear it.
one way of breaking these connections is adding onRemovedFromStage Events, that remove further children, listeners and objects. I've started using the casaLib extension of movieclip - CasaMovieClip, that has a function called removeChildrenAndDestroy. this makes it a bit easier, but would take a while to implement on an older project.
Anyhow, you'll find there are many sites discussing this, a good place to start is grant skinner's blog
So, I've been toying around with Flash, browsing through the documentation, and all that, and noticed that the ENTER_FRAME event seems to defy my expectation of a deterministic universe.
Take the following example:
(new MovieClip()).addEventListener(Event.ENTER_FRAME,
function(ev) {trace("Test");});
Notice this anonymous MovieClip is not added to the display hierarchy, and any reference to it is immediately lost.
It will actually print "Test" once a frame until it is garbage collected. How insane is that? The behavior of this is actually determined by when the garbage collector feels like coming around in all its unpredictable insanity! Is there a better way to create intermittent failures? Seriously.
My two theories are that either the DisplayObject class stores weak references to all its instances for the purpose of dispatching ENTER_FRAME events, or, and much wilder, the Flash player actually scans the heap each frame looking for ENTER_FRAME listeners to pull on.
Can any hardened Actionscript developer clue me in on how this works? (And maybe a why - the - f**k they thought this was a good idea?)
Short answer: you get what you ask for.
The fact that your MovieClip is "anonymous", as you call it, doesn't change how garbage collection works.
Both of your theories are wrong. It's simpler. You asked your MovieClip instance to notify you whenever a frame is entered. Quote from the docs:
Dispatched when the playhead is
entering a new frame. If the playhead
is not moving, or if there is only one
frame, this event is dispatched
continuously in conjunction with the
frame rate. This event is dispatched
simultaneously to all display objects
listenting for this event.
And this is what is happening.
Objects such as MovieClips are heap allocated. If you store a reference to it in a local variable, the reference lives in the stack and will get out of scope when you return from your function. You'll have no way to refer to the object, but the object will still be alive, in the heap. So, whether you store a reference to the mc instance or not, that doesn't change this basic fact of how heap and garbage collection works.
Now, since the are no strong refs to this object, this object is elligible for collection. This does not mean it will be collected when the function returns.
Since the object is still alive, it will continue to dispatch the event, because you asked for it. Once it's collected, naturally, your code in the handler will no longer be executed.
Edit
I said that both of your theories are wrong. I think that's the case from an Actionscript perspective. However, at the player level, it seems evident that the player has to keep track of objects on which it must fire certain events, so yes, it must be storing an internal reference to said objects. This is no different to how it works for other objects that are globally handled by the player, though, such as for instance, loaders. There's one exception to this that I'm aware of: running Timers. As long as a Timer is running, it won't be collected, even though you don't have any Actionscript reference to it.
I have been building a game for a while (nearly done) - But the game needs a replay button and its a big task.
I know the GC is dreadful in flash, but I wanted to know if there is a way to wipe EVERYTHING as if the flash app has just begun. Clearing memory, game data - I haven't to worry about game loading as its not really heavy on data.
Everything pretty much lives in a DataModel - but I fear if I just clear the all variables, I'll have pockets of orphaned memory.
Any forwarding idea would be great.
cheers guys.
I would do this:
make a class that encapsulates your entire game, called GameContainer or whatever.
Do a search on all your source code, and make sure that in every call to addEventListener, you are passing true for the "use weak references" argument.
In your document class (or frame script), make a single instance of GameContainer and add it to the stage, and do nothing else.
Now when you want to entirely clear your game from memory, remove GameContainer from the stage and null the reference. Memory will not immediately be released, but everything in your game will now be eligible for release. If Flash thinks it needs more memory it will trigger a GC, and the large orphaned GameContainer will be nuked. (Step 2 above will keep your event listeners from counting as references to your objects, and make sure that all self-contained objects are eligible for disposal.
Not sure what you mean about Flash's GC being dreadful though. I can't recall having heard of any bugs in it. It won't nuke your objects unless you are careful with your references, but that's true of all garbage collection.
Not short of refreshing the page. There might be some hack you could do by loading a separate swf and then unloading it, but that would be just as error prone as doing it the proper way.
My advice would be to just buckle down and write your reset function then get something to monitor memory and make sure it works by reiniting/resetting a bunch of times.
The problem with Flash's garbage collector is that as far as I know you cannot FORCE it to "collect". I had this issue with a program in which I would load in various external SWF's, and occasionally Flash would simply not load them. What you may need to do is make a function to set every major variable in your code to null at the end of a game, if you want a true reset.
There is still no guarantee, but unfortunately I'm fairly certain there is no shortcut to force a memory release.
(For me this meant also making sure my event handlers were cleared properly, and my loaders would "unload()" after passing their content off, in the case of my external SWF loader.)