Understanding Garbage Collection in AS3

Understanding Garbage Collection in AS3

Tutorial Details
  • Difficulty: Intermediate
  • Program: FlashDevelop with Flex SDK
  • Estimated Completion Time: 45 mins

Have you ever used a Flash application and noticed lag in it? Still don’t know why that cool flash game runs slowly on your computer? If you want to know more about a possible cause of it, then this article is for you.

We found this awesome author thanks to FlashGameLicense.com, the place to buy and sell Flash games!

Republished Tutorial

Every few weeks, we revisit some of our reader's favorite posts from throughout the history of the site. This tutorial was first published in June of 2010.


Final Result Preview

Let’s take a look at the final result we will be working towards:


Step 1: A Quick Run Through Referencing

Before we get into the real subject, you first need to know a bit about how instantiating and referencing works in AS3. If you have already read about it, I still recommend reading this small step. That way, all the knowledge will be fresh in your head and you won’t have trouble reading the rest of this Quick Tip!

The creation and reference of instances in AS3 is different than most people think. The instantiation (or “creation”) of something happens only when the code asks to create an object. Usually, this happens through the “new” keyword, but it is also present when you use a literal syntax or define parameters for functions, for example. Examples of this are shown below:

// Instantiation through the "new" keyword
new Object();
new Array();
new int();
new String();
new Boolean();
new Date();

// Instantiation through literal syntax
{};
[];
5
"Hello world!"
true

// Instantiation through function parameters
private function tutExample(parameter1:int, parameter2:Boolean):void

After an object is created, it will remain alone until something references it. In order to do that, you generally create a variable and pass the object’s value to the variable, so that it knows which object it currently holds. However (and this is the part most people don’t know), when you pass a variable’s value to another variable, you aren’t creating a new object. You are instead creating another link to the object that both variables now hold! See the image below for clarification:

The image assumes both Variable 1 and Variable 2 can hold the smiley (i.e. they can hold the same type). In the left side, only Variable 1 exists. However, when we create and set Variable 2 to the same value of Variable 1, we are not creating a link between Variable 1 and Variable 2 (top-right part of the image), instead we are creating a link between the Smiley and Variable 2 (bottom-right part of the image).

With this knowledge, we can jump to the Garbage Collector.


Step 2: Every City Needs a Garbage Collector

It is obvious that every application needs a certain amount of memory to run, as it needs variables to hold values and use them. What isn’t clear is how the application manages the objects that aren’t needed anymore. Does it recycle them? Does it delete them? Does it leave the object in the memory until the application is closed? All three options can happen, but here we will talk specifically about the second and third ones.

Imagine a situation in which an application creates a lot of objects when it is initialized, but once this period ends more than half of the objects created remain unused. What would happen if they were left in the memory? They would certainly take a lot of space in it, thus causing what people call lag, which is a noticeable slow-down in the application. Most users wouldn’t like this, so we must avoid it. How can we code in order to make the application run more efficiently? The answer is in the Garbage Collector.

The Garbage Collector is a form of memory management. It aims to eliminate any object that is not used and is occupying space in the system’s memory. This way the application can run with mimimum memory usage. Let’s see how it works:

When your application starts to run, it asks for an amount of memory from the system which will be used by the application. The application starts then filling this memory with any information you need; every object you create goes into it. However, if the memory usage gets close to the memory requested initially, the Garbage Collector runs, seeking any object not used to empty some space in the memory. Sometimes this causes a bit of lag in the application, due to the big overhead of object searching.

In the image, you can see the memory peaks (circled in green). The peaks and the sudden drop are caused by the garbage collector, which acts when the application has reached the requested memory usage (the red line), removing all unnecessary objects.


Step 3: Starting the SWF File

Now that we know what the Garbage Collector can do for us, it’s time to learn how to code in order to get all the benefits from it. First of all, we need to know how the Garbage Collector works, in a practical view. In code, objects become eligible for Garbage Collection when they become unreachable. When an object cannot be accessed, the code understands that it won’t be used anymore, so it must be collected.

Actionscript 3 checks reachability through garbage collection roots. At the moment an object can’t be accessed through a garbage collection root, it becomes eligible for collection. Below you see a list of the principal garbage collection roots:

  • Package-level and static variables.
  • Local variables and variables in the scope of an executing method or function.
  • Instance variables from the application’s main class instance or from the display list.

In order to understand how objects are handled by the Garbage Collector, we must code and examine what is happening in the example file. I will be using FlashDevelop’s AS3 project and Flex’s compiler, but I’m assuming you can do it on any IDE you want, since we are not going to use specific things that exist only in FlashDevelop. I have built a simple file with a button and text structure. Since this isn’t the objective in this quick tip, I will quickly explain it: when a button is clicked, a function fires. At any time we want to display some text in the screen, you call a function with the text and it is displayed. There is also another text field to show a description for buttons.

The objective of our example file is to create objects, delete them and examine what happens to them after they are deleted. We will need a way to know whether the object is alive or not, so we will add an ENTER_FRAME listener to each of the objects, and make them display some text with the time they’ve been alive. So let’s code the first object!

I created a funny smiley image for the objects, in tribute to Michael James Williams’s great Avoider game tutorial, which also uses smiley images. Each object will have a number on its head, so we can identify it. Also, I named the first object TheObject1, and the second object TheObject2, so it will be easy to distinguish. Let’s go to the code:

private var _theObject1:TheObject1;

private function newObjectSimple1(e:MouseEvent):void
{
	// If there is already an object created, do nothing
	if (_theObject1)
		return;
	
	// Create the new object, set it to the position it should be in and add to the display list so we can see it was created
	_theObject1 = new TheObject1();
	_theObject1.x = 320;
	_theObject1.y = 280;
	_theObject1.addEventListener(Event.ENTER_FRAME, changeTextField1);
	
	addChild(_theObject1);
}

The second object looks almost the same. Here it is:

private var _theObject2:TheObject2;

private function newObjectSimple2(e:MouseEvent):void
{
	// If there is already an object created, do nothing
	if (_theObject2)
		return;
	
	// Create the new object, set it to the position it should be in and add to the display list so we can see it was created
	_theObject2 = new TheObject2();
	_theObject2.x = 400;
	_theObject2.y = 280;
	_theObject2.addEventListener(Event.ENTER_FRAME, changeTextField2);
	
	addChild(_theObject2);
}

In the code, newObjectSimple1() and newObjectSimple2() are functions that are fired when their corresponding button is clicked. These functions simply create an object and add it in the display screen, so we know that it was created. Additionally, it creates an ENTER_FRAME event listener in each object, which will make them display a message every second, as long as they are active. Here are the functions:

private function changeTextField1(e:Event):void
{
	// Our example is running at 30FPS, so let's add 1/30 on every frame in the count.
	_objectCount1 += 0.034;
	
	// Checks to see if _objectCount1 has passed one more second
	if(int(_objectCount1) > _secondCount1)
	{
		// Displays a text in the screen
		displayText("Object 1 is alive... " + int(_objectCount1));
		
		_secondCount1 = int(_objectCount1);
	}
}
private function changeTextField2(e:Event):void
{
	// Our example is running at 30FPS, so let's add 1/30 on every frame in the count.
	_objectCount2 += 0.034;
	
	// Checks to see if _objectCount2 has passed one more second
	if(int(_objectCount2) > _secondCount2)
	{
		// Displays a text in the screen
		displayText("Object 2 is alive... " + int(_objectCount2));
		
		_secondCount2 = int(_objectCount2);
	}
}

These functions simply display a message on the screen with the time the objects have been alive. Here is the SWF file with the current example:


Step 4: Deleting the Objects

Now that we have covered the creation of objects, let’s try something: have you ever wondered what would happen if you actually delete (remove all references) an object? Does it get garbage collected? That’s what we will test now. We are going to build two delete buttons, one for each object. Let’s make the code for them:

private function deleteObject1(e:MouseEvent):void
{
	// Check if _theObject1 really exists before removing it from the display list
	if (_theObject1 && contains(_theObject1))
		removeChild(_theObject1);
	
	// Removing all the references to the object (this is the only reference)
	_theObject1 = null;
	
	// Displays a text in the screen
	displayText("Deleted object 1 successfully!");
}
private function deleteObject2(e:MouseEvent):void
{
	// Check if _theObject2 really exists before removing it from the display list
	if (_theObject1 && contains(_theObject2))
		removeChild(_theObject2);
	
	// Removing all the references to the object (this is the only reference)
	_theObject2 = null;
	
	// Displays a text in the screen
	displayText("Deleted object 2 successfully!");
}

Let’s take a look at the SWF now. What do you think will happen?

As you can see. If you click “Create Object1″ and then “Delete Object1″, nothing really happens! We can tell the code runs, because the text appears in the screen, but why doesn’t the object get deleted? The object is still there because it wasn’t actually removed. When we cleared all references to it, we told the code to make it eligible for garbage collection, but the garbage collector never runs. Remember that the garbage collector will only run when the current memory usage gets close to the requested memory when the application started to run. It does make sense, but how are we going to test this?

I’m certainly not going to write a piece of code to fill our application with useless objects until the memory usage gets too big. Instead, we will use a function currently unsupported by Adobe, according to Grant Skinner’s article, which forces the Garbage Collector to run. That way, we can trigger this simple method and see what happens when it runs. Also, from now on, I will refer to Garbage Collector as GC, for the sake of simplicity. Here’s the function:

private function forceGC(e:MouseEvent):void
{
	try
	{
		new LocalConnection().connect('foo');
		new LocalConnection().connect('foo');
	}
	catch (e:*) { }
	
	// Displays a text in the screen
	displayText("----- Garbage collection triggered -----");
}

This simple function, which only creates two LocalConnection() objects, is known to force the GC to run, so we will call it when we want this to happen. I don’t recommend to use this function in a serious application. If you are doing it for test, there are no real problems, but if it’s for an application that will get distributed to people, this isn’t a good function to use, since it may incur negative effects.

What I recommend for cases like this is that you just let the GC run at its own pace. Don’t try to force it. Instead, focus on coding efficiently so that memory issues don’t happen (we will cover this in Step 6). Now, let’s take a look at our example SWF again, and click the “Collect Garbage” button after creating and deleting an object.

Have you tested the file? It worked! You can see that now, after deleting an object and triggering the GC, it removes the object! Notice that if you don’t delete the object and call the GC, nothing will happen, since there is still a reference to that object in the code. Now, what if we try to keep two references to an object and remove one of them?


Step 5: Creating Another Reference

Now that we have proved that the GC works exactly as we wanted, let’s try something else: link another reference to an object (Object1) and remove the original. First, we must create a function to link and unlink a reference to our object. Let’s do it:

private function saveObject1(e:MouseEvent):void
{
	// _onSave is a Boolean to check if we should link or unlink the reference
	if (_onSave)
	{
		// If there is no object to save, do nothing
		if (!_theObject1)
		{
			// Displays a text in the screen
			displayText("There is no object 1 to save!");
			
			return;
		}
		
		// A new variable to hold another reference to Object1
		_theSavedObject = _theObject1;
		
		// Displays a text in the screen
		displayText("Saved object 1 successfully!");
		
		// On the next time this function runs, unlink it, since we just linked
		_onSave = false;
	}
	else
	{
		// Removing the reference to it
		_theSavedObject = null;
		
		// Displays a text in the screen
		displayText("Unsaved object 1 successfully!");
		
		// On the next time this function runs, link it, since we just unlinked
		_onSave = true;
	}
}

If we test our swf now, we will notice that if we create Object1, then save it, delete it and force the GC to run, nothing will happen. That is because now, even if we removed the “original” link to the object, there is still another reference to it, which keeps it from being eligible for garbage collection. This is basically all you need to know about the Garbage Collector. It isn’t a mystery, after all. but how to we apply this to our current environment? How can we use this knowledge to prevent our application from running slowly? This is what Step 6 will show us: how to apply this in real examples.


Step 6: Making Your Code Efficient

Now for the best part: making your code work with the GC efficiently! This step will provide useful information that you should keep for your entire life – save it properly! First, I’d like to introduce a new way to build your objects in your application. It is a simple, but effective way to collaborate with the GC. This way introduces two simple classes, which can be expanded to others, once you understand what it does.

The idea of this way is to implement a function – called destroy() – on every object that you create, and call it every time you finish working with an object. The function contains all the code necessary to remove all references to and from the object (excluding the reference which was used to call the function), so you make sure the object leaves your application totally isolated, and is easily recognized by the GC. The reason for this is explained in the next step. Let’s look at the general code for the function:

// Create this in every object you use
public function destroy():void
{
	// Remove event listeners
	// Remove anything in the display list
	// Clear the references to other objects, so it gets totally isolated
	
}

// ...
// When you want to remove the object, do this:
theObject.destroy();

// And then null the last reference to it
theObject = null;

In this function, you’ll have to clear everything from the object, so it remains isolated in the application. After doing that, it will be easier for the GC to localize and remove the object. Now let’s look at some of the situations in which most memory errors happen:

  • Objects that are used only in an interval of execution: be careful with these ones, as they can be the ones that consume a lot of memory. These objects exist only for some period of time (for example, to store values when a function runs) and they aren’t accessed very often. Remember to remove all references to them after you’re done with them, otherwise you can have many of them in your application, only taking memory space. Keep in mind that if you create a lot of references to them, you must eliminate each one through the destroy() function.
  • Objects left in the display list: always remove an object from the display list if you want to delete it. The display list is one of the garbage collection roots (remember that?) and so it is really important that you keep your objects away from it when removing them.
  • Stage, parent and root references: if you like to use a lot these properties, remember to remove them when you’re done. If a lot of your objects have a reference to these, you may be in trouble!
  • Event listeners: sometimes the reference that keeps your objects from getting collected is an event listener. Remember to remove them, or use them as weak listeners, if necessary.
  • Arrays and vectors: sometimes your arrays and vectors can have other objects, leaving references within them which you may not be aware of. Be careful with arrays and vectors!

Step 7: The Island of References

Although working with the GC is great, it isn’t perfect. You have to pay attention to what you are doing, otherwise bad things can happen with your application. I’d like to demonstrate a problem that may crop up if you don’t follow all the required steps to make your code work with the GC properly.

Sometimes, if you don’t clear all the references to and from an object, you may have this problem, especially if you link a lot of objects together in your application. Sometimes, a single reference left can be enough for this to happen: all your objects form an island of references, in which all the objects are connected to others, not allowing the GC to remove them.

When the GC runs, it performs two simple tasks to check for objects to delete. One of these tasks is counting how many references each object has. All objects with 0 references get collected at the same time. The other task is to check if there is any small bunch of objects that link to each other, but can’t be accessed, thus wasting memory. Check the image:

As you can see, the green objects can’t be reached, but their reference counting is 1. The GC performs the second task to check for this chunk of objects and removes all of them. However, when the chunk is too big, the GC “gives up” on checking and assumes the objects can be reached. Now imagine if you have something like that:

This is the island of references. It would take a lot of memory from the system, and wouldn’t be collected by the GC because of the complexity of it. It sounds pretty bad, huh? It can be easily avoided, though. Just make sure you have cleared every reference to and from an object, and then scary things like that won’t happen!


Conclusion

This is it for now. In this Quick Tip we learned that we can make our code better and more efficient in order to reduce lag and memory issues, thus making it more stable. In order to do this, we have to understand how referencing objects work in AS3, and how to benefit from them to make the GC work properly in our application. Despite the fact that we can make our application better, we have to be careful when doing it – otherwise it can get even messier and slower!

I hope you liked this simple tip. If you have any questions, drop a comment below!

  • http://fortheloss.org Ralph

    Nice post. I’m always worried about performance and I fear that because of this it makes me second-guess myself all the time when I’m coding.

    Anyway, I’ve always wanted to see a clear, concise post about the Garbage Collector just so I could understand it better, thanks!

    • Daniel Sidhion

      Hello, Ralph! Thank you for your comment, I’m glad it helped! :)

  • Rezmason

    Nice post.

    I’m pretty sure the GC doesn’t “give up” on objects during a mark-and-sweep. It will just take longer to perform the mark-and-sweep, so it will break the task up into bits, and it does a little bit at a time until it finishes.

    I’m sure of this because I’ve had projects where I stored thousands of unique elements in an Array, and then removed the Array from the reference tree. The GC got rid of the elements in the Array little by little.

    Regardless, you got the important thing right; nulling references is an easy way to help the GC perform its task, which will improve app performance. It helps to set the length of Arrays and Vectors to 0 before dereferencing them, as well.

    • Daniel Sidhion

      Hey Rezmason! Your comment is very interesting. I think more tests are necessary to check whether the GC gives up or not during the mark-and-sweep phase, but I think it really stops checking when it encounters a big amount of objects linking each other in a complicated way, since mark-and-sweeping takes a lot of time and performance to run. In the tests that I created here to test this, the GC didn’t collect the big “island” of objects that easily.

      However, you have a concept wrong: the mark-and-sweep phase can’t be split up into small bits. It must run through all the memory, and if it stops before completing, it needs to start it all again. You can read a bit about this in the link below, which is recommended by Colin Moock in his great book “Essential ActionScript 3.0″:

      http://www.memorymanagement.org/articles/recycle.html#mark-sweep

      I hope it helps :)

      Thank you for your comment, it’s good to see people bringing up other discussions about the subject!

      • Rezmason

        A while ago, the guys at Adobe put up some slides talking about the AVM2. They do, in fact, use an “incremental conservative mark/sweep collector”:

        http://www.onflex.org/ACDS/AS3TuningInsideAVM2JIT.pdf

        But like we both said before, what’s important is to follow the right programming practices to make the GC’s job easier, however it gets its job done.

  • Ryan

    Okay, I’m not sure if there’s just code missing, but it seems to me that the reason it keeps displaying “Object 1 is alive…3″ etc. is because in the remove reference function, it does not remove the event listener, which acts on its own, not checking to see if the object still exists. So it keeps running the function regardless of whether the object is null.

    • Daniel Sidhion

      Hello Ryan! Thank you for the comment!

      In the “deleteObject” function, we simply make the object unreachable through the root, even if it has an event listener referencing it. The purpose of the listener is to keep displaying messages as long as the object is alive, so we see the exact moment that the object gets really deleted from memory. Notice that, when we force the GC to run, the object gets deleted and the same happens with the listener. Remember that the listener is linked to the object, so it will also be alive as long as the object is.

  • Pingback: Tutorials » Blog Archive » Quick Tip: Understanding Garbage Collection in AS3

  • Dexterous

    Nice quick tip.

    I just want to add one thing here – that if you use timeOuts or intervals (by using setTimeout or setInterval), make sure to clear them by using clearTimeout or ClearInterval respectively. Otherwise the entire object (say a movieclip) cannot be removed from memory.

    • Daniel Sidhion

      Hey Dexterous, thanks for the comment and the tip!

      However, according to Colin Moock’s “Essential ActionScript 3.0″, even with a “setInterval”, an object gets removed from the memory, but it will keep performing unnecessary tasks until that happens. That is exactly what happens in the quick tip example: the event listener is still there with the object, performing an unnecessary task, theoretically, but which is useful to help us track the object after its reference with the root gets removed.

      But I agree with you that everyone should clear the timeouts and intervals (which is called “deactivating”) when disposing of objects, so that the objects don’t keep performing unnecessary tasks.

  • http://logicmania-lab.blogspot.com/ harilal

    hai ,

    it’s a wonderfull post. I love it. Because am looking for this one for may days..
    When i started in Actionscript 3.0 , am worried about the events in it. After searching i found casalib..

    it’s awsome and works great for me . it had a built in destroy() function which works perfect..

    • Daniel Sidhion

      Hey Harilal, I’m glad that the destroy() function helped you! Thank you for your comment! :)

  • drunkcat

    nice post.
    One more tip: when useing listeners, always use week reference (or remove listeners after deleting an object). so, insteed of
    _theObject1.addEventListener(Event.ENTER_FRAME, changeTextField1);
    there should be rather:
    _theObject1.addEventListener(Event.ENTER_FRAME, changeTextField1, false, 0, true );

    • Daniel Sidhion

      Hey drunkcat, thanks for the tip and the comment! It’s already in the quick tip, right in Step 6, but thanks for reinforcing it!

  • http://www.juxt2.com Dimitree

    Nice article!
    How helpful is also using weak references on event handlers? like:
    addEventListener(Event.ENTER_FRAME, eventhandler, false, 0, true);

    • Daniel Sidhion

      Hello Dimitree!

      It is recommended to always use weak listeners, because they aren’t counted as references during mark-and-sweep and reference counting steps, in the GC. Since the reference counting step has a better performance and is probably run more often, if all references of an object are weak, it will get removed during the reference counting step. However, if all the references of the same object are strong, and it can’t be reached through the root, it will only get removed during the mark-and-sweep step.

      To prove the argument, creating weak references in the example of the quick tip lets the objects get collected by the GC only a few seconds after removing their reference to the root, which is great!

      Thank you for your comment, I hope the quick tip helped you!

  • Pingback: A new post and some changes ­ Daniel Sidhion's blog

  • http://leocavalcante.com Leo Cavalcante

    Hi Daniel, nice post!
    But, what you tell about the “System.gc()” method?

    • Daniel Sidhion

      Hey Leo!

      The “System.gc()” method is only applicable to the debug versions of Flash Player and AIR applications. It works and does its job, but since you can’t force people to have the debug version of Flash Player, I wouldn’t recommend using it in your projects. It is OK if you want to use for testing purposes.

      If you want to read when you can use the “System.gc()” method without worries, check Flex Language Reference:

      http://livedocs.adobe.com/flex/3/langref/flash/system/System.html#gc%28%29

      Thank you for the comment! :)

  • http://omarfouad.com Omar Fouad

    Thanks for the post! This is what I needed to clear my doubts. However I want to be sure of something… If I have an object (ObjectWrapper) that contains other objects (Ob1, Ob2, Ob3), when I destroy ObjectWrapper, will the children objects be eligible for GCollection?

  • http://www.flickr.com/photos/elussich Esteban

    Highly recommend CASAlib framework (http://casalib.org/), they have a really nice destroy() method along with many other features.

  • http://www.stewartknapman.com Stewie

    So what happens to the memory that has been accumulated once the flash player has been closed?
    Does it know to release the memory as soon as it has been?

    If this is the case, is it possible that if I refresh my browser, any memory is released and then new memory is accessed on the reload?

    The reason I ask is that I have an instance where my movie makes a URLRequest, and if the page is refreshed before the call has returned it will crash the browser citing a memory exception (trying to access memory thats not there, or not available to it.)
    I am just trying to get my head around the cause for this.

    Note: This occurs most often with flash 10.1 on windows using IE, the interesting thing is that it wasn’t apparent (meaning it could have been happening, but nowhere near as frequently) on the same system with the previous version of flash player.

    Thanks in advance for any help.

  • http://badcoding.wordpress.com gonaku_sense

    Thanks

    Very helpful..

    i faced the condition when my game become huge memory every time T.T

    And now… my task it’s difficult. I must make many my unreachable objects! oh men..big job!

  • Giorgio

    So, if I have understood exactly, if I have a class that for example has an image container (ic) and a text field (tf) added to its display list, its destroy method may something like this?

    public function destroy():void
    {
    ic.removeEventListener(MouseEvent.CLICK,someFunc);
    removeChild(ic);
    ic = null;

    tf.removeEventListener(MouseEvent.CLICK,anyFunc);
    removeChild(tf);
    tf = null;
    }

    Thanks in advance.

    • http://michaeljameswilliams.com/ Michael James Williams

      I think that’d do it! Might be overkill if you’re going to remove the instance of the class itself and set it to null, but it shouldn’t cause any problems.

  • abhi

    I dont undershtand how exactly execution of forceGC(). how exactly it works to GC.

    Can you explain it bit more please?

  • Pingback: 谈谈ActionScript垃圾回收(上) | free your mind…

  • http://www.kac.fr LePioo

    Truely f*****g great!
    A lot of questions are answered now, thx

  • Pingback: Understanding Variables, Arrays, Loops, and Null: The Post-it Note Analogy

  • Pingback: How to Learn Flash and AS3 for Game Development | Gamedevtuts+

  • Romeo

    Great article, thank you for this!