Fixing Memory Leaks with Adobe Flash Builder

On a recent project, we had a performance problem. The AIR project’s requirements include the heavy adding/removing of UI elements and over time we could easily see the performance slowed. We knew there was a something wrong. It was a memory leak. A memory leak starts when an object is stored in memory but cannot be accessed by the running code. When the undesired object cannot be freed from memory, and is not usable, it is a leak. Over time the application may leak (or re-leak the same issue) more and more. Eventually the application may show signs of the leak or even become unusable.

User Experience Symptoms Of  A Memory Leak

  • During regular use the application becomes more and more sluggish/slow. If there is nothing ‘new happening’ onscreen and no heavy ‘rendering’ it is more obvious to notice the Framerate-per-second (FPS) lower. You can use a small debug window (such as Hi-Res-Stats formerly MrDoobs Stats) to show the current FPS and estimated ram usage to help you notice this. If you see the FPS run at 30 for example during the first minute of use and 20 after 5 minutes, there may be a memory leak.
  • The application quits suddenly. This could be for many reasons, but it may be that the application runs out of memory.
  • Flash throws the memory-specific error ‘flash.errors.MemoryError’
Even if you see one of these symptoms it may not be obvious that there is a problem or that the problem is a memory issue. Or perhaps your development machine is high powered with ample RAM, yet your target user’s machines are slow. You don’t see the issue, but your users will. So how can we diagnose the issue. Luckily, the Flash Builder IDE has a ‘Profiler’. This program runs alongside your application and serves several key roles. You can monitor your applications USAGE of memory over time, and see a live list of all OBJECTS in memory (including references to those objects).

Profiling To Find Evidence Of A Memory Leak

  • Run your application with the Flash Builder Profiler. Run -> Profile As… -> etc…
  • Watch the ‘Memory Usage’ Panel
  • Look at the curves of Peak Memory (Red) and Current Memory (Blue). The analysis is totally application dependent. In your particular application, if you expect memory not to grow, but you see it grow, that is a problem. If you expect the memory to drop (UI removed from stage, arrays and vectors emptied, etc…) and you don’t see it drop, that is a problem. Herein lies the art of memory profiling. Consider to add a button to ‘Reset Application’, then click it and see that indeed the Current Memory drops to zero (0).
  • Watch the ‘Live Objects’ panel. Compare the 1. ‘Cumulative Instances’ and 2. ‘Instances’. For each object. #1 shows the total objects every created since the application started and #2 shows only those currently in memory. If these numbers are the same, and should not be, that is a problem. Perhaps you feel you have deleted a sprite from the stage or deleted another object from memory yet it still exists.


Tools And Tips For Finding And Fixing Memory Leaks (Must Read!)

If you want to play with a simple example you can download the example below (See ‘Member Resources’) below.

Example 1: Without Memory Leak

[actionscript3]
package
{
import flash.display.Sprite;
import flash.events.Event;

//USE A LOW FRAMERATE, SO WE CAN STUDY CLOSELY
[SWF(frameRate="1")]
public class MemoryLeakDemo extends Sprite
{

private var listOfDots_vector:Vector.<CustomDot>;
public function MemoryLeakDemo()
{
//REPEAT SOME CODE EVERY SECOND
addEventListener(Event.ENTER_FRAME, _onEnterFrame);

//CREATE A LIST
listOfDots_vector = new Vector.<CustomDot>();
}

protected function _onEnterFrame(event:Event):void
{
//EVERY FRAME WE…

//1. CREATE A NEW ‘DOT’ (A Red Circle Sprite)
//MEMORY NOTE: ‘var’ is a temporary variable.
//So CustomDot has 0 (permanent) references
var customDot : CustomDot = new CustomDot();

//2. ADD TO THE STAGE
//MEMORY NOTE: So CustomDot has 1 (permanent) reference; ‘this’
addChild(customDot);

//3. REMOVE TO THE STAGE
//MEMORY NOTE: So CustomDot has 0 reference
removeChild(customDot);

//So…
//THERE IS NO LEAK
//The GC will *mark* the ‘customDot’ as having 0 references and
//The GC will *sweep* it away from memory.

}

}
}
[/actionscript3]

Example 2: With Memory Leak

[actionscript3]
package
{
import flash.display.Sprite;
import flash.events.Event;

//USE A LOW FRAMERATE, SO WE CAN STUDY CLOSELY
[SWF(frameRate="1")]
public class MemoryLeakDemo extends Sprite
{

private var listOfDots_vector:Vector.<CustomDot>;
public function MemoryLeakDemo()
{
//REPEAT SOME CODE EVERY SECOND
addEventListener(Event.ENTER_FRAME, _onEnterFrame);

//CREATE A LIST
listOfDots_vector = new Vector.<CustomDot>();
}

protected function _onEnterFrame(event:Event):void
{
//EVERY FRAME WE…

//1. CREATE A NEW ‘DOT’ (A Red Circle Sprite)
//MEMORY NOTE: ‘var’ is a temporary variable.
// So CustomDot has 0 (permanent) references
var customDot : CustomDot = new CustomDot();

//2. ADD TO THE STAGE
//MEMORY NOTE: So CustomDot has 1 (permanent) reference; ‘this’
addChild(customDot);

//2B. CREATE ANOTHER REFERENCE TO THE DOT
listOfDots_vector.push(customDot);

//3. REMOVE TO THE STAGE
//MEMORY NOTE: So CustomDot has 0 reference
removeChild(customDot);

//So…
//THERE *IS* A LEAK
//While we are correctly calling removeChild
//There is a reference left in ‘2B’ above.

}

}
}
[/actionscript3]

Next Steps

  • Download the code and check it out! (See Member Resources)
  • Comment below with your thoughts.
  • NOTE: Flash Builder 4.7 (BETA2) has new Profiler called “Monocle“. It looks very exciting, yet this article focuses on the currently available (non-BETA) profiler.

Member Resources

[private_Free member]Enjoy this members-only content!

[/private_Free member]