Flash Builder 4 Profiler: how to spot what objects are causing a known memory increase?
Asked Answered
F

2

11

I know profiler questions can be quite general, but here I have a very specific question and example.

I know that in the following code (taken from Joshua's question), that an infinite number of circle object instances are being added to the hostComponent. This obviously causes gradual slowing down of the app.

My question is, when I run the Flash Builder Profiler, where exactly do I see where the problem lies?

Running example of the app

To try it out, create a new Flex 4 project, and paste in this code:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
               initialize="onInit()" viewSourceURL="srcview/index.html">
    <fx:Script>
        <![CDATA[
            import mx.core.UIComponent;
            import mx.effects.Fade;         
            import spark.effects.Move;

            private var hostComponent:UIComponent;

            private function onInit():void{

                hostComponent = new UIComponent();
                hostComponent.id = "circleHostComponent";
            }

            /* Add circle UIComponent objects to the hostComponent.
                Move and Fade the circle objects */
            private function onTimerEvent(event:TimerEvent):void{  

                var yPos:Number = Math.ceil(Math.random()*100);
                var radius:Number = Math.ceil(Math.random()*5); //1-12
                var effectAlpha:Number = Math.random()*0.5 + 0.2 // 0-1
                var effectDuration:Number = Math.ceil(Math.random()*3000) + 1000;

                var circle:UIComponent = new UIComponent();
                circle.graphics.beginFill(0x1C75BC, effectAlpha);
                circle.graphics.drawCircle(90, yPos, radius);
                circle.graphics.endFill();

                hostComponent.addChild(circle);

                var moveEffect:Move= new Move(circle);
                moveEffect.xBy = 300;
                moveEffect.duration = effectDuration;

                moveEffect.play(); 

                var fadeEffect:Fade = new Fade(circle);
                fadeEffect.alphaFrom = 1;
                fadeEffect.alphaTo = 0;
                fadeEffect.duration = effectDuration;

                fadeEffect.play();

                this.addElement(hostComponent);

            }

            private function onClick():void{
                startButton.enabled = false;
                var t:Timer = new Timer(100, 0);
                t.start();
                t.addEventListener(TimerEvent.TIMER, onTimerEvent);

            }       

        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>

    <s:Button id="startButton" label="Click to Start" click="onClick()" />
</s:Application>
Fever answered 10/2, 2011 at 15:10 Comment(1)
Can't wait to see an answer to this one. I've had very little luck deciphering the output of the profiler. +1 for a good question.Kommunarsk
F
10

First, I would look at the Memory Usage panel after playing a bit with the application :

enter image description here

Notice the memory increases more and more. There is a "Run Garbage Collector" button that forces the GC. However, when you click on it, the memory doesn't decrease.

The next step is to identify the culprits. For that, you use the Live Objects panel :

enter image description here

It looks like that, appart some Vector instances, everything looks allright. By default, a lot of classes are filtered from the live objects datagrid. Fortunately, one can specify which classes will be displayed and hidden. All classes from the flash.x.x packages are hidden by default. Removing them from the filtered list bring somthing interesting to the table :

enter image description here

Notice the Graphics row : 871 instances have been created and they are all still in memory! With that info, you can suppose the Graphics instances are responsible of the slow down of the application. If you also filter out the mx.* classes, you will see there are 871 UIComponents instances. Everytime a UIComponent is created, there is a Graphics object also instancied.

Final step is to remove each UIComponent once it's no more needed on screen and look if there is any performance improvement.

Filmer answered 13/2, 2011 at 16:43 Comment(2)
+1 Removing filtering gave much more info. On Run Profiler config options, tick 'Generate object allocation trace'. Take two memory snapshots, select both, click find Loitering Objects. Use allocation trace to see when the uiComponents are created (on timer tick) - this points one in right direction.Fever
Will post a screenshot of how to find the exact culprit in a moment.Fever
F
8

Flash Builder Profiler

  1. Run the application using Profiler (choose the option to Generate object allocation trace when asked)
  2. Take two Memory Snapshots af few seconds apart
  3. Select both of the Memeory Snapshots and click Find Loitering Objects
  4. Make sure to click Filtering, and remove any filters
  5. Sort by memory. UIComponent will be top/close to top of the list
  6. Double click UIComponent in the Loitering Objects window - this brings up Object References window.
  7. Click a UIComponent under Instances and view its Allocation Trace, this will let you know where that UIComponent was created (if you double click on the Allocation Trace view where it gives you the line number - 30 in this case - it opens that location in Source view).

Now you know the source of the memory problem

To fix the accumulative memory leak, add the following:

After fadeEffect.play(); add

fadeEffect.addEventListener(EffectEvent.EFFECT_END, onEffectEnd);

and add the function:

private function onEffectEnd(event:EffectEvent):void
{
   trace(hostComponent.numChildren);
   hostComponent.removeChild(event.target.target);
   event.target.target = null;
}
Fever answered 14/2, 2011 at 13:12 Comment(2)
Yep, the compare memory snapshots feature usually helps a lotFilmer
I might just add (or else I've missed something) - step 4 must be done before step 2, or else the snapshots will be filtered and won't contain all the objects.Agglomeration

© 2022 - 2024 — McMap. All rights reserved.