Flash Builder 4 Profiler:如何发现哪些对象导致已知的内存增加?

发布于 2024-10-16 13:33:21 字数 3016 浏览 4 评论 0原文

我知道探查器问题可能非常笼统,但这里我有一个非常具体的问题和示例。

我知道在下面的代码中(取自 Joshua 的问题),无限数量的circle对象实例被添加到hostComponent。这显然会导致应用程序逐渐变慢。

我的问题是,当我运行 Flash Builder Profiler 时,我到底在哪里看到问题所在?

应用程序的运行示例

要尝试一下,请创建一个新的 Flex 4 项目,然后粘贴此代码:

<?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>

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

余厌 2024-10-23 13:33:21

首先,在玩了一下应用程序后,我会查看“内存使用情况”面板:

在此处输入图像描述

注意内存增加越来越多。
有一个“运行垃圾收集器”按钮可以强制执行 GC。然而,当你点击它时,内存并不会减少。

下一步是找出罪魁祸首。为此,您可以使用“活动对象”面板:

在此处输入图像描述

看起来像这样,分配一些 Vector 实例,一切看起来好的。
默认情况下,许多类是从活动对象数据网格中过滤出来的。幸运的是,我们可以指定要显示和隐藏哪些类。
默认情况下,flash.xx 包中的所有类都是隐藏的。从过滤列表中删除它们会给表格带来一些有趣的东西:

在此处输入图像描述

注意图形行:871 个实例已被删除创建并且它们仍然在记忆中!有了这些信息,您就可以假设 Graphics 实例是导致应用程序速度减慢的原因。如果您还过滤掉 mx.* 类,您将看到有 871 个 UIComponents 实例。每次创建 UIComponent 时,都会实例化一个 Graphics 对象。

最后一步是在屏幕上不再需要每个 UIComponent 后将其删除,并查看是否有任何性能改进。

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.

陌生 2024-10-23 13:33:21

Flash Builder Profiler

  1. 使用 Profiler 运行应用程序(在询问时选择生成对象分配跟踪选项)
  2. 间隔几秒钟拍摄两个内存快照
  3. 选择两个内存快照并单击查找徘徊对象
  4. 确保单击“过滤”,然后删除所有过滤器
  5. 按内存排序。 UIComponent 将位于列表顶部/接近顶部
  6. 双击“​​徘徊对象”窗口中的 UIComponent - 这将打开“对象引用”窗口。
  7. 单击实例下的 UIComponent 并查看其分配跟踪,这会让您知道
    UIComponent 的创建位置(如果双击 Allocation Trace 视图,其中会显示行号 - 在本例中为 30 - 它会在 Source 视图中打开该位置)。

现在您知道内存问题的根源

要修复累积内存泄漏,请添加以下内容:

在 fadeEffect.play(); 之后添加

fadeEffect.addEventListener(EffectEvent.EFFECT_END, onEffectEnd);

并添加功能:

private function onEffectEnd(event:EffectEvent):void
{
   trace(hostComponent.numChildren);
   hostComponent.removeChild(event.target.target);
   event.target.target = null;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文