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

Posted

技术标签:

【中文标题】Flash Builder 4 Profiler:如何发现导致已知内存增加的对象?【英文标题】:Flash Builder 4 Profiler: how to spot what objects are causing a known memory increase? 【发布时间】:2011-06-24 22:24:22 【问题描述】:

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

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

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

Running example of the app

要试用它,请创建一个新的 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>

【问题讨论】:

迫不及待地想看到这个问题的答案。我几乎没有运气破译分析器的输出。 +1 提出一个好问题。 【参考方案1】:

    使用 Profiler 运行应用程序(在询问时选择生成对象分配跟踪选项) 每隔几秒拍两张内存快照 选择两个内存快照并单击查找游荡对象 确保点击过滤,然后删除所有过滤器 按内存排序。 UIComponent 将在列表顶部/接近顶部 在 Loiting Objects 窗口中双击 UIComponent - 这将打开 Object References 窗口。 点击Instances下的一个UIComponent,查看它的Allocation Trace,这会让你知道 该 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;

【讨论】:

是的,比较内存快照功能通常很有帮助 我可能只是添加(否则我错过了一些东西) - 步骤 4 必须在步骤 2 之前完成,否则快照将被过滤并且不会包含所有对象。【参考方案2】:

首先,我会在使用该应用程序后查看内存使用面板:

注意内存越来越多。 有一个强制 GC 的“运行垃圾收集器”按钮。但是,当您单击它时,内存不会减少。

下一步是找出罪魁祸首。为此,您可以使用 Live Objects 面板:

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

注意 Graphics 行:871 个实例已经创建,它们都还在内存中!有了这些信息,您可以假设 Graphics 实例是导致应用程序变慢的原因。如果您还过滤掉 mx.* 类,您将看到有 871 个 UIComponents 实例。每次创建 UIComponent 时,都会实例化一个 Graphics 对象。

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

【讨论】:

+1 删除过滤提供了更多信息。在运行探查器配置选项中,勾选“生成对象分配跟踪”。拍两张内存快照,都选中,点击find Loiting Objects。使用分配跟踪查看 uiComponents 的创建时间(在计时器滴答时) - 这指向正确的方向。 稍后将发布如何找到确切罪魁祸首的屏幕截图。

以上是关于Flash Builder 4 Profiler:如何发现导致已知内存增加的对象?的主要内容,如果未能解决你的问题,请参考以下文章

Flash Builder 4.5 与 Flash?

使用SparkSession.builder时如何设置profiler_cls?

解决flash builder 4.6调试不可用

Flash builder 4.6 Fake flex 错误

Flash builder 4.6 到 Eclipse indigo

Flash Builder 4.5 - 无法导入外部类?