Memory Profiling Flex Apps

Introduction

In a Flex application, the programmer decides when to allocate memory, simply by using the new operator. However, the developer has absolutely no control over when the memory is freed, because it is done by the “Garbage Collector”.

The Garbage Collector

The GC uses a ‘mark and sweep’ method, which requires at least two passes:

The first pass starts at a set of known “top-level” points (Stage, child objects, static variables and local variables) and traces down through all the referenced objects and marks them as it goes. It’s interesting to note that local variables are included in this pass – more on that in the next sections.

The second pass iterates over the entire list of allocated objects, and decides how many of these (if any) need to be freed up to satisfy the current memory request.

To complicate matters further, the memory allocation process allocates in large chunks and then sub-allocates those chunks for smaller objects. The GC will only delete objects when they are in a chunk where all the objects within it are marked for deletion.

Memory Profile of a Flex App

Memory Profile of a Flex App

This results in strange behaviours that you can see in the Flex profiler – the total memory will appear to increase and then suddenly drop as a chunk is released. Eventually, the system will reach a point where the system can satisfy every memory request by freeing up other chunks.

 

Ensuring that an object is free to be collected

For an object to be marked by the first pass of the GC, it must have no references from the top level objects. Prime candidates for stopping an object being collected are as follows:

  • Static variables
  • Class variables
  • Event listeners

This last point requires clarification.

It is the event dispatcher that holds a reference to the listening class (not the other way around)

public class PopupWindow extends TitleWindow
{
     public function PopupWindow()
     {
         super();
         addEventListener( FlexEvent.CREATION_COMPLETE, onCreationComplete);
     }
     public function onCreationComplete(event:Event):void
     {
     }
}

This PopupWindow will be collected without any problem because the addEventListener() call adds a reference to itself.

public class PopupWindow extends TitleWindow
{
    public function PopupWindow()
    {
        super();
        stage.addEventListener(MouseEvent.CLICK, onMouseClick);
    }
    public function onMouseClick(event:MouseEvent):void
    {
        trace("Stage mouse-click");
    }
}

This one won’t. The reason is that stage now has a reference to an instance of PopupWindow. As stage will never go away during the life of the application, neither will an instance of PopupWindow.

Further considerations

The Garbage Collector is called as a result of something calling the new operator, not as a background task. In other words, the system wants more memory, so it goes about seeing if it can make any room elsewhere before allocating a completely new block. So if the application is sitting idle, you won’t see the memory change at all in the Profiler.

This is why local variables are included as “top level” objects, because they will still be referencing objects at the point where new is called.

You have no control over when an object is freed. So don’t expect the count of instances to go to 0 when you think that all the references have been removed. You will have to wait until the system decides that it needs to free up those memory block to satisfy another request.

 

Markable Objects

Markable Objects

The first pass of collection traces down objects from the top level and marks them. In other words, ”’any”’ objects that don’t have a chain of references from a top level object can be marked for deletion.   In the diagram here, the objects in white can be marked for deletion, even though they have a circular link, because there is no link to the root object.

 

 

 

 

Effects

Effects can be a major contributor to memory leaks because they retain references to the target UI object. In addition, the EffectsManager listens for resize events and can then restart an effect so that it does not end when you expect it to, thus retaining a reference.

Make sure you use the in-built effects if possible, for example creationCompleteEffect and removedEffect as these are fired at the correct time by the framework, and cleared up afterwards as well.

Links

This Powerpoint presentation Garbage Collection by Alex Harui gives some background into how the garbage collector works and what needs to happen to free up objects.

This tutorial here has a lot of info on how garbage collection works, and I nicked some pictures from it…

Responses

  1. thank you, very interesting idea

  2. Do you have an example how to set up the profiler and test it?

    • Not immediately available, no. However, there is tons of documentation on LiveDocs….

      • That doesn’t seem to be helping my mate. Apparently he needs to have a static IP and all sorts to get any progress from it?


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: