I’ve been playing around with AS3 for a while now, and am really excited by its capabilities. The raw execution speed by itself will create so many possibilities. Toss in E4X, Sockets, ByteArrays, new display list model, RegEx, a formalized event and error model, and a few dozen other features for flavour, and you have a pretty heady brew.
With great power comes great responsibility, and this will be very true for AS3. A side effect of all this new control is that the Garbage Collector is no longer able to make as many assumptions about what it should tidy up automatically for you. This means that Flash developers moving to AS3 will need to develop a very strong understanding of how the GC operates, and how to work with it effectively. Building even seemingly simple games or applications without this knowledge can easily result in SWFs that can leak like a sieve, hogging all of a system’s resources (CPU/RAM), and causing the user’s system to hang (potentially even forcing them to hard reboot their computer).
- Part 1: The FP9 Garbage Collector
- Part 2: Resource Management Issues in FP9
- Part 3:New Tools in AS3
- Soon: Strategies and Solutions
Related articles
Over the next few weeks (or even months), I will be writing a series of articles on this topic. I will look at the underlying mechanics of the Garbage Collector, discuss the issues you are likely to face, examine the new tools available to you for handling resource management in AS3, and offer solutions/code to help you circumvent many of the common problems you will face.
I’ll begin at the beginning, and look at the Garbage Collector in the Flash 9 player.
About the Garbage Collector
The garbage collector is a behind-the-scenes process that is responsible for deallocating the memory used objects that are no longer in use by the application. An inactive object is one that no longer has any references to it from other active objects. In order to understand this, it is very important to realize that when working with non-primitive types (anything other than Boolean, String, Number, uint, int), you are always passing around a reference to the object, not the object itself – deleting a variable removes the reference, not the object. This is easily demonstrated:
// create a new object, and put a reference to it in a: var a:Object = {foo:"bar"} // copy the reference to the object into b: var b:Object = a; // delete the reference to the object in a: delete(a); // check to see that the object is still referenced by b: trace(b.foo); // traces "bar", so the object still exists. |
If I were to delete “b” as well in the example above, it would leave my object with no active references and free it for garbage collection. The AS3 GC uses two methods for locating objects with no active references: Reference counting and mark sweeping.
Reference Counting
Reference counting is one of the simplest methods for keeping track of active references, and has been around in Flash since AS1. When you create a reference to an object its reference count is incremented. When you delete a reference, its reference count is decremented. If the reference count of an object reaches zero, it is marked for deletion by the GC. For example:
var a:Object = {foo:"bar"} // the object now has a reference count of 1 (a) var b:Object = a; // now it has a reference count of 2 (a & b) delete(a); // back to 1 (b) delete(b); // down to 0, the object can now be deallocated by the GC |
Reference counting is simple, doesn’t carry a huge CPU overhead, and works well in most situations. Unfortunately it really falls down when it comes to circular referencing. This is when objects cross-reference each other (directly, or indirectly via other objects). Even if the application is no longer actively using the objects, their reference counts remain above zero, so they are never removed. Here’s a quick demo:
var a:Object = {} // create a second object, and reference the first object: var b:Object = {foo:a}; // make the first object reference the second as well: a.foo = b; // delete both active application references: delete(a); delete(b); |
In the above example, both of my active application references have been deleted. I no longer have any way of accessing the two objects from my application, but their reference counts are both 1 because they reference each other. This can also be much more complex (a references c which references b which references a, etc), and is hard to deal with in code. Flash player 6 and 7 suffered from problems related to circular referencing in XML objects – each XML node referenced both its children and its parent, so they were never deallocated. Fortunately, player 8 added a new GC technique called mark sweeping.
Mark Sweeping
The second strategy employed by the AS3 (and fp8) GC to find inactive objects is mark sweeping. The player starts at the root node of your application (which is conveniently the “root” in AS3), and walks through every reference on it, marking each object it finds. It then iterates through each of the marked objects, marking their children. It continues this recursively until it has traversed the entire object tree of your application, marking everything it finds. At the end of this process, it can safely assume that any objects in memory that are not marked no longer have any active references to them, and can be safely deallocated. You can see how this works in the diagram below (green references were followed during mark sweeping, green objects are marked, white objects will be deallocated).
Mark sweeping is very accurate, but because it has to traverse your entire object structure, it is also costly in terms of CPU usage. Flash player 9 reduces this cost by carrying out iterative mark sweeping (ie. it occurs over a number of frames, instead of all at once), and by only having it run occasionally.
Deferred GC and Indeterminacy
A *very* important thing to understand about the Garbage Collector in FP9 is that it’s operations are deferred. Your objects will not be removed immediately when all active references are deleted, instead they will be removed at some indeterminate time in the future (from a developer standpoint). The GC uses a set of heuristics that look at RAM allocation and the size of the memory stack (among other things) to determine when to run. As a developer, you must accept that fact that you will have no way of knowing when (or even if) your inactive objects will get deallocated. You must also be aware that inactive objects will continue to execute indefinitely (until the GC deallocates it), so code will keep running (ex. enterFrames), sounds will keep playing, loads will keep happening, events will keep firing, etc.
It’s very important to remember that you have no control over when your objects will be deallocated, so you must make them as inert as possible when you are finished with them. Strategies to manage this will be the focus for a future article.
Thanks Grant.
I’ve created an as3 documenter in flex and well we can say there is a lot of internal craziness and things happening.
This article cleared some things up with me about the garbage collector.
I also learned something else and this dosn’t have much to do with the GC but does have to do with statelessnes.
I think sometimes when your right in the middle of a large project, you sometimes forget about references to BIG object.
One mistake I made was referencing a FileManager.fileQueueCollection in a quasi analyzer framework. When I started debugging and using ObjectUtil.toString() I realized I thought I was removing references to the .as file’s loaded data that I parsed but, I was actually keeping them in memory through a statefull reference back to the FileManager.
This is where that singleton design pattern for managers can really save the day to eleiminate the state references when you just were tired one day and coded something stupid 😉
Thanks for your insane articles and showing some things that are not directly availble to a lot of developers(IE mechanics of the avm)
Peace, Mike
very interesting article. THANK YOU! stef
Nice. Very interesting article! Cant wait for futures articles …
Ales
Really interesting
Perhaps you know something about that : While i use delete in my code, and compiler strict mode on, i’ve got that error :
Attempt to delete the fixed property a. Only dynamically defined properties can be deleted.
In AS3 Language Reference (for the beta3) there no mention about delete except in Compiler Errors :
1189 > Delete removes dynamically defined properties from an object. Declared properties of a class can not be deleted. This error appears only when the compiler is running in strict mode.
Is it means that only dinamically defined properties can be deleted by this way ?
Does my objects really deleted after calling delete if delete do his job only for dinamically defined properties ?
It seems strange to me, especially after reading your post…
Cédric – good question. I started typing a reply, and decided it might warrant it’s own post… stand by.
UPDATED: see next post “Understanding the Delete Keyword”
I’m just wondering why Flash doesn’t give you the control of the actual memory now?
It seems it would be easier to delete the object from memory yourself, then to have to disable everything it runs to get it to stop. And then delete.
Very interesting though.
“they will be removed at some indeterminate time in the future (from a developer standpoint)” …. I’ll take it that can mean from several milliseconds to several seconds?
Very interesting article! Curious to read the next one!
Sascha,
It could be anything from a few milliseconds to hours. It is determined by heuristics that are mostly based on RAM usage. If you carry out a lot of RAM intensive activities, the GC will sweep more often.
I am working on Flex migration from 1.5 to 2.0. and i want to delete dynamice property. how can i do it?
this is exactly the explanation I have been searching for, thank you very much, very beneficial article for flash developers
Do you know if FCS/FMS uses only the reference counting method?
Few thoughts…
Because objects don’t get deleted straight away, Ive always taken the approach of setting things I want deleted immediately to null… that way, the object may or may not be deleted straight away, but its contents *are* deleted straight away. That is, ‘if you cant delete the container, the next best thing is to make the container empty’.
eg
rather than
delete foo;
I do
foo = null;
delete foo;
Im not sure how valid my assumptions here are, but its certainly reduced the memory usage in a couple of Flash 7 based web applications I’ve developed in the past, particularly when there’s constant XML traffic.
Shamb,
The delete operator will take care of it; there’s no need to set the variable to null. Remember that when you set
foo = {greeting:”Howdy};
and then later on call
foo = null;
What you’re doing in the second case is operating on the variable, not the object. If you wanted to clear out the object, you’d have to null out each of the object’s properties.
In your case, what you’re doing is deleting a variable that’s a null reference. Same diff to the garbage collector; the object the variable originally pointed to was already cut loose as soon as you said “foo = null”.
Shamb – Chris is correct. It should have no impact on the collection of objects whether you set your properties to null or delete them. Both approaches have the effect of removing the reference to the object, not removing (or modifying) the object itself.
Of course, in AS3 you can only delete dynamic properties, so setting to null becomes the norm.
this is exactly the explanation I have been searching for, thank you very much, very beneficial article for flash developers
info
what’s about this
var a:*=new Application();
where application is a class…how can i remove this then ?
We have just updated our game to Flash 9. It has become impossible to play in internet explorer. The problem seems to be that the garbidge collection sweeps the memory every second this makes the processor usage jump between 20% and 80%. This does not happen in other browsers. We have not been able to find a solution.D oes anybody else have this problem with IE / AS3?
Is the GC for JVM and AS work in the same way
Thank you.
Do Loader objects with event listeners attached (eg Event.COMPLETE) persist as long as the load operation is underway? I have code that includes a Loader within a function with the onComplete listener function nested within that function and it has never failed, but some advise that this practice is risky. I seem to remember AS2’s load functions working the same way as my AS3 example above seems to be working– that they do persist until the load event is executed.
Thanks for the article– very helpful.
hi i just read your article , very interesting but 1 thing made me very confused …
in the example where you do :
var a:Object = {foo:”bar”}
var b:Object = a;
delete(a);
delete(b);
right there you are deleting 2 objects that are static right ?
i try it i get the 1189 error (which i was expecting)
so the example doesn’t actually work right ?
or am i the only one experiencing this problem ?
by reading the comments i guess i should do
a = null;b = null; to make it eligable for deallocation ?
These are just the kind of headaches that the java applet community went through (the past tense refers more to the death of java applet development, rather than the problems ever being solved)
Considering Flash’s background as an creative tool that traditionally allowed loose coding standards, I’m surprised Adobe allowed this backdoor to remain so open. Along with the recent security issues, allowing untrusted code that is assumed to run in a sandbox to bring down the VM and/or the OS, could tarnish Flash reputation as a must have plugin. Rather corporate IT administrators may start to view it in the same light as they do Java applet plugin, and a drop in corporate desktop (ie middle income advert viewers) penetration will hurt the whole flash development industry.
There are some pretty hardcore memory management debugging tools for java, including those that emulate the garbage collectors sweep through the object tree, so developers can see linkages that prevent unloading.
Grant, can you give us some clues as to what will be coming up in your Strategies and Solutions post?
Wery nice article.
Thanks!!
hi,i have a question about addeventlistener
obj.addEventLisener(..listener);
obj = null;
i want to know why gc won’t clean obj?
i think addlistener means obj have a reference to listener (function object), just like obj have other parameters, when obj is null, no reference to obj, so gc should clean obj
or addlistener, the listener(function obj) will have a reference to the obj? or other reasons?
hehe,that great. thanks.
Great article Grant – as usual. Hey what plans for the UML tool extension plans for AS3?
where’s the last article with title “Strategies and Solutions”?…this is really wierd.
Wow! this actually really makes sense.
So – since I can’t in no way controll a thing in flash – How do I go about deleting those stinky things?
hi
how this garbage collections are used in our loader or the Movieclips?..
Thanks
Karthick Raj.S
Useful, Nice Informational Article.
This post comes up in the google search result “as3 memory management” right in the first place. You should update it to the present reality of the Flash Player 10, even if we must have the same careful approach with the new player, if I’m not wrong we have new things like invoking System.gc() among others? How to use System.gc() efficiently?
Great article. Looks like there are issues when the GC don´t work properly when using bytesArray and swfloaders. Deleting swfloaders or clearing them from data won´t always “mark” loaded data (note: loaded with byteAray) as garbage. Very odd.
This article is just curiously, i think.
who could give some sample, a full-application, which is optimized with the numerous waste resources?
Great article. Thanks for sharing this info. Somehow, adobe’s own documentation lacks in clarifying certain things.
No one replied to Aaike’s post on January 16, 2008. I am getting the same problem as hers! I get the 1189 error, basically.. delete a, and delete b do NOT work and I turn into an error. It only works if I do
delete a.foo
delete b.foo
So in response to mine and Aaike’s post , will the GC collect the garbage if we set a = null, and b = null as well? Simple question deserves a simple answer. Thanks =)!
I did use some smart garbarge collection in my Smooth xml image gallery: http://bit.ly/7aWzXt ; it took a lot of time to set everything straight 🙂
I came across the following “feature” in Flash 10, compiling with Flash IDE CS4:
Take the following code as your starting position:
//——————-
var obj:Object = new Object();
var prev:int = 0;
trace( ‘var obj:Object = new Object();\t–> ‘ + System.totalMemory );
prev = System.totalMemory;
obj.sound = new Sound();
trace( ‘obj.sound = new Sound();\t\t–> ‘+ System.totalMemory + ‘(‘+(prev ‘ + System.totalMemory + ‘(‘+(prev
I would absolutely love to be able to view those reference counts in a debugger.
Mark, have you checked out the profiler in Flash Builder? It will give you the number of references, where they’re from, etc.
Thanks, it’s very helpful for me.
http://www.as3tutorial.com is very helpful for beginners.
I would absolutely love to be able to view those reference counts in a debugger.
This blog is dead. And you will be dead soon too (not really)