[Flex] Top 5 memory leaks in Flex, #5:

Issue: When using states in mxml, components that have been added with the <mx:AddChild> tag, can not be cleanly removed and therefore they stuck in memory

Tested version: Flex Milestone 3.2

Workaround: Unfortunately there is none. Either you do not use States any more or you compile your own Flex-SDK and fix the classes DeferredInstanceFromFunction and DeferredInstanceFromClass, which holds instances of your added component, even when the corresponding state is not active any more. Another possibility would be to create your own AddChild class that does not use the DeferredInstance classes, see Nick Bilyk’s blog post: Flex states retaining memory

Note: These is the (shortened) source code of DeferredInstanceFromClass (nearly same source in DeferredInstanceFromFunction), where I’ve highlighted the retained reference to the instance that has been created. I have no idea why they store the instance in a private variable, must be some performance intentions.

package mx.core
{

public class DeferredInstanceFromClass implements IDeferredInstance
{

[..]

private var instance:Object = null;

/**
*    Creates and returns an instance of the class specified in the
*  DeferredInstanceFromClass constructor, if it does not yet exist;
*  otherwise, returns the already-created class instance.
*
*  @return An instance of the class specified in the
*  DeferredInstanceFromClass constructor.
*/

public function getInstance():Object
{

if (!instance)
     instance = new generator();

//this should be: return new generator();
return instance;

}

}

}

[Flex] Top 5 memory leaks in Flex, #4: effects

Issue: Running effects prevent components from being garbage collected

Tested version: Flex Milestone 3.2

Workaround: Call end()-method of effect before removing the component.

Note: This example consists of 2 files and extends the example from the previous post by a simple effect. The main application (nothing changed here), seen in the first box, adds the self made-component from box 2. It uses a move effect, that restarts automatically and a timer to demonstrate how this combination could lead to memory leaks. Like in the previous blog post, it is also necessary to nullify the component after removing it from the display list, otherwise it will remain in memory, even when listeners are correctly removed and effects are not running any more!

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” width=”150″ height=”150″ xmlns:local=”*”>

<mx:Script>
<![CDATA[

private function remove():void
{

myComponent.destroy();
removeChild(myComponent);

//IF NOT NULLIFIED, then no garbage collection!!!
myComponent = null;

}

]]>
</mx:Script>

<mx:Button label=”Remove component” click=”remove()” />

<local:MyComponent id=”myComponent” y=”50″ />

</mx:Application>

package
{

import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.controls.Label;
import mx.core.UIComponent;
import mx.effects.Move;
import mx.events.EffectEvent;

public class MyComponent extends UIComponent
{

private var myTimer:Timer;
private var myMoveEffect:Move;
private var label:Label;
private var i:uint = 0;

public function MyComponent()
{

label = new Label();
label.setActualSize(100,20);
addChild(label);

myTimer = new Timer(100,999);
myTimer.addEventListener(TimerEvent.TIMER, onTimer);
myTimer.start();

myMoveEffect = new Move();
myMoveEffect.addEventListener(EffectEvent.EFFECT_END, onEffectEnd);
myMoveEffect.duration = 3000;
myMoveEffect.xBy = 100;
myMoveEffect.play([label]);

}

private function onTimer(event:TimerEvent):void
{

i++;
label.text = i.toString();

}

private function onEffectEnd(event:EffectEvent):void
{

if (myMoveEffect.xBy > 0)
myMoveEffect.xBy = -100;
else
myMoveEffect.xBy = 100;
 
myMoveEffect.play([label]);

}

public function destroy():void
{

if (myTimer)
{

myTimer.removeEventListener(TimerEvent.TIMER, onTimer);
myTimer.stop();

}

if (myMoveEffect)
{

myMoveEffect.removeEventListener(EffectEvent.EFFECT_END, onEffectEnd);
myMoveEffect.end();

}

}

}

}