Hi Folks,

I've been hunting memory leaks in a large application for my company
(shame on Adobe for not putting in an option for weak references in
ChangeWatchers!) and have noticed something.  If you use a binding or
changeWatcher or standard event listener on a popUpWindow, you of course
get a nasty memory leak.  However, I'm finding that even if you avoid
such things, popping up and closing a window continuously does in fact
cause a very slight but very real memory leak over time.

Running the following application over ten minutes shows a rise in about
five megs of memory.

Can anyone confirm that they've seen something like this?  Is this
something that just has to be lived with, or is there a way to ensure
that standard use of the flex components doesn't cause leaks?

<!-- MyApp.mxml -->

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
     xmlns:mx="http://www.adobe.com/2006/mxml";
     xmlns:local="*"
     creationComplete="addObject()"
     layout="vertical">
     <mx:Script>
         <![CDATA[
             import mx.containers.TitleWindow;
             import mx.managers.PopUpManager;
             import flash.utils.setTimeout;

             public var popUps:Array = []

             public function addObject():void
             {
                 var dialog:TitleWindow = new TitleWindow();
                 PopUpManager.addPopUp(dialog,this);
                 popUps.push(dialog);

                 setTimeout(removeAllObjects,50);
             }

             public function removeAllObjects():void
             {
                 for each(var item:TitleWindow in popUps){
                     PopUpManager.removePopUp(item);
                 }
                 popUps = [];

                 setTimeout(addObject,50);
             }

         ]]>
     </mx:Script>
     <local:MemoryMonitor id="mm" creationComplete="mm.start()"
width="100%" />
</mx:Application>





<!-- MemoryMonitor.mxml -->

<?xml version="1.0" encoding="iso-8859-1"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml";
creationComplete="init()">
<mx:Script>
<![CDATA[
     import mx.collections.ArrayCollection;

     private var timer:Timer;
     private var maxmem:Number = 0;
     private var lasttotal:Number = 0;
     private var initYet:Boolean = false;
     private var startTime:Number = new Date().getTime();
     private var startBytes:Number = System.totalMemory;

     [Bindable]
     private var seriesArray:ArrayCollection=new ArrayCollection([]);
     private var counter:int=0;

     public var maxPoints:Number = 100;


     private function fullGC():void
     {
         // unsupported hack that seems to force a full GC
         try
         {
             var lc1:LocalConnection = new LocalConnection();
             var lc2:LocalConnection = new LocalConnection();

             lc1.connect('name');
             lc2.connect('name');
         }
         catch (e:Error)
         {
         }
     }


     private function timerHandler(event:Event):void
     {

         var totalmem:Number = System.totalMemory;
         lasttotal = totalmem;
         total.text = totalmem.toString();
         maxmem = Math.max(maxmem, System.totalMemory);
         max.text = maxmem.toString();

         if(counter++%10==0){
             fullGC();
             setMin();
         }
         seriesArray.addItem({time:new Date().getTime(),
value:totalmem});
         var len:int = seriesArray.length;
         if(len>=maxPoints){
             var rand:Number = Math.random();
             // remove a fairly recent random point
             var index:int =
Math.floor((1-rand*rand*rand)*(maxPoints-1));
             seriesArray.removeItemAt(index+1);
         }

         if (callbackFunction != null)
             callbackFunction();
     }

     private function setMin():void
     {
         var min:Number = -1;
         for each(var item:Object in seriesArray){
             if(min==-1)
                 min = item.value;
             else if (min>item.value)
                 min = item.value;
         }
         LinearAxis(chart.verticalAxis).minimum = min;
     }

     public var interval:int = 100;
     public var callbackFunction:Function = null;

     public function start():void
     {
         timer = new Timer(interval);
         timer.addEventListener("timer", timerHandler);
         timer.start();
     }

     public function stop():void
     {
         timer.stop();
         timer.removeEventListener("timer", timerHandler);
         timer = null;
     }


]]>
</mx:Script>
<mx:HBox>
     <mx:Label text="current memory:" />
     <mx:Label id="total" text="0" width="100" />
     <mx:Spacer width="20" />
     <mx:Label text="max memory:" />
     <mx:Label id="max" text="0" width="100" />
     <mx:Spacer width="20" />
     <mx:Button label="resetChart" click="seriesArray.removeAll()" />
</mx:HBox>
<mx:LineChart id="chart" height="100" width="100%" showDataTips="true"
>
     <mx:horizontalAxis>
         <mx:DateTimeAxis />
     </mx:horizontalAxis>
     <mx:verticalAxis>
         <mx:LinearAxis />
     </mx:verticalAxis>
     <mx:series>
         <mx:LineSeries dataProvider="{seriesArray}" xField="time"
yField="value"/>
     </mx:series>
</mx:LineChart>
</mx:VBox>


Reply via email to