views:

392

answers:

7

I've been programming in ActionScript for about 6 years now but never heard of the term 'garbage collection' until AS3 came out. Why do we have to worry about it now, and never before? And what, precisely, is it? From what I've read/heard, it has something to do with memory management/leaks, etc. -- and even that I don't understand much of, other than it has something to do with performance.

I recently launched a site for an artist friend of mine, and it was done in AS3. I am noticing that it takes up a LOT of resources. Obviously this is something I'd like to improve. I'm guessing it has something to do with the fact that there is no garbage collection going on?! Unfortunely, I haven't the slightest idea on where to begin in regards to that, as I feel I need a better undestanding of what it is and how to go about doing it specifically in AS3.

For the curious, here is the URL: http://www.jeffperrott.com

A: 

I don't know anything about the AP3 implementation, but someone has to post this :)

http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

Basically, you work with pointers (well, references) to data. A reference that goes out of scope will be deleted. Whenever no references points to data, the data will be marked for garbage collection. Your GB-thread (process or daemon) will in time release all resources used to allocate the marked data.

cwap
A: 

Normally you, or your development runtime has to manually handle memory at some point, wither that be to create a space for your applications data in memory or clear memory from use once your application is done with it. If there is no GC (garbage collector) in the runtime you are required to manually handle the creations and removal of memory spaces for your variables and objects in your application.

An example is Native C++. Before C++ programmers can really do much with the application they have to make the ground work that deals with memory themselves. They ask the OS for memory, they add allocations, they add objects and data to memory, they remove objects and data later, they unallocate memory, they clean it up and release it to the OS again.

With a GC the GC does all that work for you. All you do is tell the GC (usually through instancing an object) that you are planning to use memory and the GC figures out how much memory you need, asks the OS for it, allocates and adds your data. It then checks from time to time if your application is still using that object. If it's not then it removes the object, unallocates, cleans it up and releases back to the OS. All this is done for you so you, the programmer, can just focus on your program. An example of this is VB 6.0 and C#/VB.NET.

EDIT: This is an extremely simplified explaination. There is actually alot more to it then this but this answer should answer the basic question asked here.

Phillip
+6  A: 

The Garbage collector is the part of the runtime (in your case the Flash or AIR player) that cleans up unused memory. ActionScript has always had garbage collection like all scripting languages (e.g. javascript, perl, ruby, etc..) you just don't see it discussed much for AS.

The basic idea is that every object created takes some memory, and your variables keep reference to those objects. An object's memory is not "released" back into the pool of available memory until there are no more references to it. The garbage collector keeps track of which objects have references to them, and at various intervals will reclaim the memory of those with zero references (i.e. no variables pointing to it, so no code can even find it to use it). If there is are any references* the object's memory cannot be reclaimed, in case some part of your code decides to use it in the future.

If your program appears to be leaking memory (constantly growing, never stabilizing in size or shrinking) then it's possible you are placing objects in a hash or array, or some other collection object. This object obviously maintains a reference to it's contents, so those things are never deleted.

Note that in ActionScript it is easy to create "leaks" by using closures as event handlers. If your handlers can access variables which are assigned but never nulled, those variables keep their references, and the objects they point to will not be garbage collected as long as the event handler is registered.

function registerHandler(neverReleased:Object) {
    ...
    addEventHandler(function (e:Event) {
            ...
        });
}

Invoking the Garbage Collector directly is almost always a bad thing(tm), the garbage collector in Flash/Flex is very good. First find out where your objects are being held, and release them, letting the GC work on it's own schedule.

*Except for circular references which is a bit out of this answer's scope.

Chadwick
A: 

Adding to Chadwick's answer:

If you addEventHandler to an image but don't removerEventHandler when the image is no longer displayed, the memory occupied by the image cannot be recovered by the garbage collector.

Peter W A Wood
In AS3 you can choose to create a weak reference to your event listener which would allow the image (for example) to be garbage collected.
Richard M
It is addEventListener, and it is the other way around. The function listening for the event will not be collected as long as the image exist.
Lillemanden
You are absolutely correct. Thanks for pointing out my mistakes.
Peter W A Wood
+2  A: 

Grant Skinner has a useful set of posts on AS3 resource management, which cover the garbage collector among other topics: http://www.gskinner.com/blog/archives/2006/06/as3_resource_ma.html

Richard M
+2  A: 

Every time you use the "new" keyword to create an object, you're staking your claim on a piece of memory [1]. So let's say you're making a uint by writing var exampleUint:uint = new uint();. ActionScript says to the computer "hey... I need like... four bytes of memory.", to which the computer replies "ok cool, use the four bytes starting at [some memory address, like 0x7B3208C1]"[2]. So when you say var someString:String = "blah"; you claim a space in memory, fill it with some information (in this case, it's "blah"), create a label (in this case, it's someString), and bind the label to that space in memory.

Now the label doesn't actually associate to the data itself, it associates to the spot in memory containing the data. That should seem confusing, because it is, but it makes a whole shit-ton of sense for certain reasons. All objects in ActionScript are reference types, which means that the object contains the memory address of some piece of data, not the data itself. This is in contrast to objects that are value types, where a label associates to the data itself. Don't fret about the details on value types because it's not in ActionScript so for your purposes I'm including it strictly for contrast. OK, confused? You probably should be, because this whole paragraph is needlessly specific and probably even unnecessary, but try to keep it in the back of your head because it may have something to do with your problem.

Now, when that label is gone (e.g., it goes out of scope, so now someString is meaningless), only the label someString is removed. So for this example, if you say someString = null;, the string "blah" is actually still in memory, but the label someString doesn't reference that piece of information, it references the memory address of the null object(again, details). We need a way to specify to the computer "you know the [whateverSize] piece of memory I claimed starting at [whateverAddress]? Well I'm done with it now so somebody else can use that piece of memory". Gabage collection is an automatic process for reclaiming memory that you've claimed without having to worry about it yourself. In languages without garbage collection, new has a complement keyword that specifically frees the memory associated to an object [3], but ActionScript doesn't have that; you just take a piece of memory and forget about it.

Somewhere along the lines, you may have created another variable and referenced that piece of data, var someOtherString:String = someString;, so we can't just say "ok, the label someString is gone, so let's get rid of the data that it references", because we don't know for sure that someString is the only reference to that data. The method in which this is done varies between languages and garbage collection systems, but the basic deal in ActionScript is this: every now and then (especially if Flash is currently taking up a lot of memory), the garbage collector looks at all of the objects in the current SWF and finds all of the objects that don't have any reference [4]. So for our previous example, if someString was the only thing that referenced the string "blah" and someString goes out of scope, then "blah" isn't associated to any label and is therefore totally unreachable by Flash. The next time the garbage collector runs, it will find that and then report back to the system that it's done with that piece of memory.

Now, the specific details of your particular problem would be hard to say without looking at the source, but I can tell you that one of the things that often causes problems is event listeners. Sometimes you might create a function and add it as an event listener. Now the event itself has a reference to that function [5], so if the function goes out of scope, there's still a reference to it and the function does not get picked up by the garbage collector (remember, functions are objects in ActionScript). You can either remove event handler manually by calling removeEventListener (I wouldn't recommend it), or set the useWeakReference parameter in you calls to addEventListener() to true. A weak reference is not recognized by the garbage collector, so setting useWeakReference to true prevents the situation where you have a function that should be picked up by the garbage collector, but it doesn't because someone is referencing it as an event listener. Judging by the sheer number of mouseEvent listeners in your project, this could be the culprit. If you have Flex Builder, you can use the profiler to see how many method closures you have; if they're going up and never coming down, that's probably your problem.

[1]: Keep in mind that this also applies to situations where you create an object without using the new keyword, like if you were to write var exampleInt:int = 5;.
[2]: I chose uint because all uints are the same size, so I can say with confidence that I know it will be four bytes. Strings are different; they take up an amount of memory proportional to the number of characters they contain, so it would be a little more ambiguous to use String for both examples.
[3]: The ActionScript keyword delete is not for this purpose, so don't try to use it in this way, even though that would make perfect logical sense and it would be very useful.
[4]: Flash uses a mark-and-sweep style strategy, the more specific details of which can be read here. [5]: Actually, that's a boldface lie because the addEventListener method uses closures, but I have a pretty weak understanding of that to begin with so I can't really boil it down into normal person English.

jorelli
A: 

Just to help you understand why you haven't heard of this before, in previous versions of AS the GC was deeply linked to the display list. Once you removed an object from the scene, it no longer existed (along with any child objects), and any reference to them was turned to null. This behaviour, as you may already know, is quite the opposite in AS3. Good luck!

Cay