ActionScript
Forcing Garbage Collection In Flash (AS3)
April 9, 2009
0

Flash Garbage Collector executes at unpredictable times.  The engineer at Adobe have alleviated this somewhat with the introduction of System.gc(); command.  See the reference at:

http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/System.html#gc()

I won’t argue whether it is a good or bad idea to call the garbage collector manually.  I many cases, it is not necessary.  However, I believe that there are situations where calling the garbage-collector is needed.  For example, if my application is unloading a movie and I know the next movie will be large; I would rather be able to call the garbage-collector before the next movie starts playing (say before preloading the next movie).  Otherwise, I risk the large-movie being interrupted by the garbage collector during playback (which may cause choppiness).

Another important reason for forcing garbage-collection is to check memory usage during development phase.

gc (Note: Flex Builder’s Profiler has a Garbage Collect button so you don’t necessarily have to use System.gc() if you’re debugging using Flex Builder’s Profiler).

Let’s assume for the sake of this article, that you do want to force garbage-collection and decided to use System.gc().  You might encounter these problems:

Problem1

This error comes up compiling.

1061: Call to a possibly undefined method gc through a reference with static type Class

Suggestion: update your Flash SDK because your System class does not have gc() method.

Problem2

System.gc() is only valid if your user has an newer version of the Flash Player 9.0.115.0,  ADL, or Flash Player 10.  If you add it in your code blindly, you risk causing error during playback, which may produce this kind of error (end user don’t usually see this error, unless they have a Debug Flash Player):

TypeError: Error #1006: gc is not a function.

You can, of course, always comment out the call when you’re ready to release the product.  But there are several other solutions:

Suggestion 1: Use conditional compilation that only enables the call in debugging phase.  See here for how to use conditional compilation arguments.

Suggestion 2: Create a function (which can be in a utility class) and put the System.gc() call inside a try and catch block.  This way, the application will fail gracefully if the command isn’t found.

function callGarbageCollector():Boolean
{
 try
 {
   System.gc()
   return true;
 }
 catch (e:Error)
 {
   return false;
 }
}

Problem3

Memory does not seem to decrease after System.gc().
Possible solution: In some earlier Flash Player versions, you have to call System.gc() twice for it to take effect.  You can see the memory usage by using System property, or by installing helpers like SWF Profiler.

Related Notes

The memory management in Flash Player is still notoriously difficult (http://blogs.adobe.com/aharui/2007/03/garbage_collection_and_memory.html, and http://www.gskinner.com/blog/archives/2008/04/failure_to_unlo.html).

It is important to remember that the garbage-collector will not garbage-collect any memory that is still being referenced.  It only releases memory that are no longer referenced, which is not necessarily the ones you might think will be removed.  Think about this.  If you have a variable named myMovieClip that points to MovieClip.swf, then MovieClip.swf will not be garbage collected because the compiler doesn’t know if you’re still going to use myMovieClip in the future.   Therefore, try to follow memory managements best-practices, such as:

  • Remove all event listeners.
  • Stop all MovieClip and sounds.
  • Nullify all references to every MovieClip.
  • Detach movie clips from their parents.
  • Avoid static variables or isolate them on a separate class.
  • Stop all timers that is being referenced by a movie clip.

If you’re using the new unloadAndStop() method (see Adobe doc also), remember that it won’t work on Flash Player 9, so enclose it within try and catch block so that older player won’t give errors.

try
{
 movieClip.unloadAndStop();
}
catch (e:Error)
{
}