Archive

Posts Tagged ‘flex’

Flex Memory Management and Memory Leaks

November 14, 2011 Leave a comment

You probably heard, read or even learned that Flex was managing the memory automatically for you, does it mean you don’t have any responsibility regarding memory management in Flex? Absolutely not!

If you’re surprised by my answer, keep reading to understand how memory is managed in Flex using garbage collection, what responsibilities this is putting on developers, what the classical causes of memory leaks are and what are the good practices to enhance or optimize the memory management in your applications.

 

Let’s start by clarifying how Flex manages the memory before discussing common best practices regarding memory management in Flex applications.

Flex Memory Management

Flex Memory Allocation principles

The Flash Player is responsible for providing memory for your flex application at runtime. The memory that the Flash Player provides to Flex applications must be requested to the computer’s operating system. Knowing that OS memory allocation is a slow operation, the Flash Player is using a buffering technique to avoid requesting frequent allocations.

This technique consists in managing two different types of memory: the OS memory1 and the Application memory. The OS memory is requested by the Flash Player in big chunks for performance reasons and kept as a memory pool in which Flex objects can be allocated.

At startup, the Flash Player initializes the Application memory pool. Then, as the application creates objects, the pool is used to provide memory for the new objects. In case the pool wouldn’t have enough available memory for a new object, the Flash Player requests a new big chunk to the operating system.

Allocating Memory in Flex: OS and Application memory pools

When your Flex application deletes some objects, the Flash Player doesn’t release the corresponding OS memory but just makes it available for any further allocation (i.e. the memory is back in the Application pool). The OS memory is released only if a complete big chunk is not used anymore by your application.

Freeing Memory in Flex: OS and Application memory pools

To conclude on the Flex Memory Allocation topic, it must be mentioned that in Flex, you cannot explicitly delete an object (or free a chunk of memory). Object deletion, and related memory release operation, is automatically managed by the Flash Player itself, using a particular mechanism called Garbage Collection2.

Flex Garbage Collection

Creating objects in Flex is an explicit operation that you trigger by calling the new operator. On the other hand, deleting an object is not an explicit operation (i.e. there is no deleteoperator3.

It’s the Flash Player itself that is responsible to check which objects are useless and delete them. This mechanism is called Garbage Collection. Basically, a useless object is an object that is not anymore referenced by another active object (i.e. orphan objects). Identification of these orphan objects is a complex task and we’ll see later how you, as a developer, can help the Flash Player to make it efficient.

The global Garbage Collection process can be seen as a two steps process. The first step being to identify the useless objects; and the second simply consisting in releasing the corresponding memory. As we saw when detailing Flex Memory Allocation principles, the memory retrieved when a useless object is deleted becomes available for a future allocation or, in some cases, can be released at the operating system level.

Marking Objects for Deletion

The first step, usually known as “Marking objects for deletion”, is implemented using the two following procedures:

Reference Counting

Reference counting is one of the simplest methods for keeping track of active references. When a strong reference to an object is created, the object reference count is incremented. When a strong reference to an object is removed, the object reference count is decremented. If the reference count of an object reaches zero, it is marked for deletion.

This is simple, fast and efficient but limited since it doesn’t work for circular references (cross references between orphan objects). This is why the Flash Player supports a second garbage collection procedure called Mark and Sweep.

Note: References can also be Weak References.

Mark and Sweep

This second garbage collection procedure works in a reversed way compared to the Reference Counting since it relies on identifying objects that are still accessible somewhere in the object tree of the application.

The Flash Player starts at the root node of the application, and goes 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 the application, marking everything it finds.

At the end of the process, if an object in memory has not been marked, it means that no active reference to the object was found. So, such objects can be marked for deletion.

Deleting Marked for Deletion objects

The second step of the Flex Garbage Collection process consists in deleting the objects that have been marked for deletion.

It is key to understand that this second step is a deferred operation. This means that objects are not deleted immediately when all active references are deleted. The deletion phase may happen at some “indeterminate” time in the future (yes, I said may because there are cases in which the deletion phase will never be executed).

The Flash Player uses a set of heuristics that look at RAM allocation, the size of the memory stack and different other criteria to determine when to trigger the deletion.

This is very important since it means that your objects, even when not referenced anymore, may continue to live for some time. It is then key to make such objects inactive so that they do not keep consuming CPU before they really be deleted (marked for deletion objects still receive events for example; the only difference compared to normal objects is that they won’t be rendered).

Garbage Collection Triggering

There is no way to force garbage collection for a production application. System.gc() is available but enabled only when the application runs in debug mode.

Anyway, when debugging applications, it may in some cases be useful to explicitly trigger the garbage collection. In such a case, you must know that calling System.gc() does not trigger the garbage collection in a synchronous way but queues the GC request such that it be executed on the next frame. You’ll often see people calling System.gc() twice in a row and explaining that the first call is for garbage marking and the second for garbage sweeping but, to my understanding, it does not work except if you wait for the next frame to call System.gc()again.

In addition to being an automatic process, there is no guarantee that all Garbage Collection steps be completed in one run. Most of the time, the Flash Player will execute the Garbage Collection in several incremental steps.

The last key characteristics of the Flex Garbage Collection process is that it is triggered only when allocating. This means that memory is not released when it not used anymore, but, instead, when more memory is requested by the application.

Note: Grant Skinner created a Garbage Collector Interactive Simulator that nicely illustrates these principles.

Best Practices regarding memory management

Now that we discussed how memory is managed in Flex using garbage collection, let’s see what developers can do to help the garbage collection process and to limit memory leaks in their applications.

Reduce consumption

The first easy way to reduce memory issues is just to allocate objects only when needed. This means deferring object allocation until really necessary (in createChildren() for example). This may seem obvious but is not always done correctly since the Flex Component Life Cycleremains a mystery for some of us.

The second good way of reducing memory consumption is by recycling objects. Instead of releasing an old object and creating a new one, it is more efficient trying to reuse the already allocated object by resetting its properties. This can be done on a case by case basis for limited recycling or by implementing pools of reusable objects when manipulating a big number of instances. The Flex framework implements such a pool concept for item renderers by recycling them when scrolling a List or a DataGrid instead of allocating one renderer for any item in the container.

Cleaning up released objects

Whenever an object is released, you should ensure that it is removing all references it holds on other objects. We’ll see below what should be released and how but let’s first highlight that the complex part here is often determining when an object is released.

What I mean is that there is no destructor available in Flex, so a given object has no direct way of knowing that it has been released. In consequence, when developing a custom component, it is not always possible to ensure that releasing it is also releasing all referenced objects.

To workaround this, a very common approach is to implement (and document) a clean up interface that developers using your custom component must call when they want to release an instance of your custom component.

IDisposable interface

Such an interface usually offers a single method, dispose() or destroy(), in which you implement all the necessary clean up: stop timersremove event listenersunload loader objectsset variable references to null, … It’s then up to developers using your component to call the dispose() method just before releasing your object.

01 public interface IDisposable {
02     function dispose():void;
03 }
04
05 public class MyComponent implements IDisposable {
06
07     // Implements dispose method that must be called just before
08     // releasing a MyComponent object
09     public function dispose():void {
10         // Clean up:
11         //      - Remove event listeners
12         //      - Stop timers
13         //      - Set references to null
14         //      - ...
15     }
16
17     ...
18 }

Managing Event Listeners

Event listeners are probably the most common cause of memory leaks in Flex applications. Adding an event listener creates a reference to the object holding the handler that may prevent the garbage collection until it is removed (i.e. the dispatcher references the listener).

You should always remove event listeners that are no longer needed. For events that are fired only once, remove the event listener in the handler associated to the event:

01 public function MyComponent():void {
02     // Listen for CREATION_COMPLETE event
03     addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
04 }
05
06 public function creationCompleteHandler(event:FlexEvent):void {
07     // Stop listening to CREATION_COMPLETE event
08     removeEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
09
10     // initialization code...
11 }

For events that you must process regularly during the life of your component (such as Timers, or mouse events), clean them up in your dispose() method.

Note: Listeners on child objects generally do not cause memory leaks but it is anyway a good practice to remove them explicitly.

Using Weak References

When calling addEventListener(), you can force the reference that will be created on your callback to be a weak reference (by setting the fifth parameter of addEventListener() to true).

Weak references are not counted as strong references are. It means that an object that has no remaining strong reference to it but only weak references will be marked for deletion.

Many of us are complaining that the weakRef parameter should have true as its default value and it’s quite common considering always using weak references as a good practice; anyway, using weak references is not without potentially nasty consequences.

First of all, you should never use weak reference for an anonymous handler:

1 addEventListener("eventName", function(event) { ... code ... }, false, 0, true);

In this example, the only reference to the function is a weak reference, meaning that next time the garbage collection runs, the function will be removed, and so, not be called anymore. Anyway, I really consider that using anonymous functions is not recommended.

Now, even when using weak references for your event listeners, you should explicitly clean them up when they are no longer needed (remember that the object removal is not predictable).

Note: Weak references are also supported in the Dictionary object. To use weak references in a dictionary, just set the first parameter to true when calling the dictionary constructor.

Using ADDED_TO_STAGE and REMOVED_FROM_STAGE events

Event.ADDED_TO_STAGE is only dispatched when a Display Object is added to the Display List and all its parents are also in the Display List4.

Event.REMOVED_FROM_STAGE is dispatched when an object or any of its parents is removed from the Display List5.

These events can be used to optimize the management of event listeners. When the object is on the stage, ensure that it listens to events, when it is not, stop listening to events (except for Event.ADDED_TO_STAGE of course).

01 // Disabling of event listeners while object is not on the stage
02 // to avoid consuming unnecessary CPU cycles
03
04 // Wait for ADDED_TO_STAGE event before enabling listeners
05 public function MyComponent():void {
06     // Listen for ADDED_TO_STAGE event
07     addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
08 }
09
10 // When removed from stage, disable all listeners except ADDED_TO_STAGE
11 private function removedFromStageHandler(event:Event) {
12     // Stop listening to REMOVED_FROM_STAGE
13     removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
14     // Remove all event listeners that are not needed while the object is
15     // not on the stage
16     removeEventListener(...);
17     // Listen to ADDED_TO_STAGE
18     addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
19 }
20
21 // When added on stage, (re)enable all listeners
22 private function addedToStageHandler(event:Event):void {
23     // Stop listening to ADDED_TO_STAGE
24     removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
25     // Enable all event listeners used by the object when it is on the stage
26     addEventListener(...);
27     // Listen to REMOVED_FROM_STAGE
28     addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
29 }

I initially thought that Event.REMOVED_FROM_STAGE could be considered as a destructor but this is not the case! When an object is re-parented (moved from A to B), it will receive anEvent.REMOVED_FROM_STAGE (when removed from A) followed by an Event.ADDED_TO_STAGE(when added as a child of B).

Note: This may also happen when objects are part of a container supporting scrollbars. When the container is resized, scrollbars may appear or disappear. In such a case, all children of the container may be re-parented in/out an internal content pane created/deleted by the resized container.

Unloading loaders

Whenever using an object based on a loader (ImageSWFLoader, …), you should always call theunloadAndStop() method to unload the content from the loader and help the garbage collection.

Managing Variable References

When releasing an object, you should clean up references that it was holding in variables.

1 // Clean up variable references
2 myObject = null;
3 myArray = [];
4 ...

Summary

Flex developers are not responsible of allocating and freeing memory since this is done by the Flex framework using a Garbage Collection mechanism. But Flex developers are anyway responsible of helping the garbage collection by carefully managing data allocation and references clean up.

Managing references efficiently and identifying memory leaks is not an easy task. Fortunately, some tools are available to help us among which I strongly recommend the Flex Profilerprovided with Flex Builder.

List of footnotes:

  1. OS memory stands for Operating System memory []
  2. There two classical ways to handle memory allocation. With languages such as C++ the developer is responsible of allocating and freeing memory. With Flex or Java, the memory is managed at runtime using garbage collection that automatically takes care of allocating or freeing memory. []
  3. There is a delete operator in Flex, but it’s only for freeing dynamic properties, not for deleting objects. []
  4. Event.ADDED is dispatched even if the parent is not yet on the Display List []
  5. Event.REMOVED is not dispatched when the parent is removed from the Display List []