1 Reply Latest reply on Apr 3, 2007 1:42 AM by fsbmain

    Memory leak in Mxml components (all good in the same AS)

    fsbmain
      I have problem in Flex 2.0 project - memory leaks, all tabs in TabNavigator aren't deleted from memory by GC, after removed from display list (using removeChild method). I'm sure i haven't external links to tabs and tabs don't listen external dispatchers without "useWeakReference=true" parameter, but however all tabs stay hang in memory. I start work with this problem and found interesting thing in simple demo (I don't know while is this somehow correlated with memory leaks in my project) - first added mxml tab _with children_ will never deleted from memory, but all good with empty mxml component (mx:VBox for instance) or any AS components - whether with children or not. Please comment this behavior, is it bug of framework?

      Demo code and instuctions:
      Application:

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application
      xmlns:mx=" http://www.adobe.com/2006/mxml"
      applicationComplete="init(event)" xmlns:local="*">
      <mx:Script>
      <![CDATA[
      import mx.containers.VBox;

      [Bindable]
      private var totalMemory:uint = 0;

      [Bindable]
      private var logEnabled:Boolean = true;

      private var timer:Timer = new Timer(500, 0);
      private function init(event:Event):void
      {
      Application.application.stage.frameRate = 1;

      timer.addEventListener(TimerEvent.TIMER, flushLog);
      timer.start();
      }

      private var logStr:String = '';
      private function flushLog(event:Event):void
      {
      log(logStr);
      logStr = '';
      }
      private function enterFrameHandler(event:Event):void
      {
      totalMemory = Math.round(System.totalMemory/1024);

      logStr+=event.type+ ' '+getTimer()+' '+ totalMemory+'kb, '+event.target+'\n';
      }

      private var arr:Array = [];
      private function fill(event:Event):void
      {
      for(var ii:uint=0; ii<20000; ii++)
      arr.push(new Sprite());
      }
      private function free(event:Event):void
      {
      arr = [];
      }

      private var counter:uint = 0;

      private var dispatcher:EventDispatcher = new EventDispatcher();
      private function add(event:Event):void
      {

      var box:VBox;
      box = (mxmlBox.selected) ? new MxmlBox() : new AsBox();

      box.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);

      box.id = box.name = box.label = 'child'+counter;
      tabNavigator.addChild(box);
      counter++;
      }

      private function remove(event:Event):void
      {
      if(tabNavigator.numChildren > 1)
      {
      var i:uint = tabNavigator.numChildren-1;
      var child:DisplayObject = tabNavigator.removeChildAt(i);
      }
      }

      public function log(txt:String):void
      {
      if(logEnabled)
      logOut.text+=txt;
      trace(txt);
      }

      ]]>
      </mx:Script>

      <mx:ApplicationControlBar>
      <mx:Button click="fill(event)" label="allocate some memory (init GC)" />
      <mx:Button click="free(event)" label="free memory" />
      <mx:Button click="add(event)" label="add tab" />
      <mx:Button click="remove(event)" label="remove tab" />
      <mx:RadioButtonGroup id="boxGroup"/>
      <mx:RadioButton groupName="boxGroup" label="add MXML box" id="mxmlBox" selected="true" />
      <mx:RadioButton groupName="boxGroup" label="add AS Box" id="asBo" selected="false"/>

      </mx:ApplicationControlBar>
      <mx:TabNavigator id="tabNavigator"
      width="100%" height="100%"
      styleName="processTabNavigator"
      >
      <mx:VBox label="Log">
      <mx:TextArea borderStyle="none" id="logOut" width="100%" height="100%"/>
      <mx:HBox>
      <mx:Button label="clear" click="{logOut.text=''}" />
      <mx:Button label="{logEnabled ? 'stop' : 'start'}" click="{logEnabled=!logEnabled}" />
      <mx:Label text="{'Memory usage : '+totalMemory+' kb'}"/>
      </mx:HBox>
      </mx:VBox>
      </mx:TabNavigator>
      </mx:Application>

      MxmlBox,mxml:

      <?xml version="1.0" encoding="utf-8"?>
      <mx:VBox
      xmlns:mx=" http://www.adobe.com/2006/mxml"
      >
      <mx:Button label="button" />
      </mx:VBox>



      AsBox.as

      package
      {
      import mx.containers.VBox;
      import mx.controls.Button;

      public class AsBox extends VBox
      {
      public function AsBox():void
      {
      }

      override protected function createChildren():void
      {
      var btn:Button = Button(addChild(new Button()));
      btn.label = 'button';
      }
      }
      }


      Demo instructions:
      1) Add 3-6 children to TabNavigator by clicking on "addTab" button, u can add mxml or as child by select appropriate radioButton.
      2) See log in first tab marked "log" - each tab writes own output until it will be removed from display list and deleted memory
      3) delete all tabs from displayList by clicking "remove tab" button, log tab will not be deleted.
      4) After adding tabs press "allocate some memory (init GC)" button, this will force GC to clean memory. If GC doesn't inited click any more times on allocate/free some memory buttons
      5) See, that only first mxml tab write log - this meas it still hangs in memory.

      U can remove mx:Button child in MxmlBox component to sure that it'll solve first tab problem.