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

11
我知道性能分析器的问题可能很普遍,但这里我有一个非常具体的问题和示例。
我知道以下代码(取自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>

2
迫不及待地想看到这个问题的答案。我在解密分析器的输出方面运气很差。为一个好问题点赞。 - Wade Mueller
2个回答

10

首先,我会在使用应用程序一段时间后查看"内存使用"面板:

enter image description here

注意到内存不断增加。 有一个"运行垃圾回收"的按钮可以强制进行GC。但是,当你点击它时,内存并没有减少。

下一步是识别罪犯。为此,您可以使用"实时对象"面板:

enter image description here

除了一些Vector实例外,一切看起来都很好。 默认情况下,许多类从实时对象数据网格中筛选出来。幸运的是,可以指定将显示和隐藏哪些类。 flash.x.x包中的所有类默认情况下都是隐藏的。将它们从过滤列表中删除,可以获得有趣的信息:

enter image description here

请注意Graphics行:已创建871个实例,并且它们仍然在内存中!通过这些信息,您可以推测Graphics实例负责导致应用程序变慢。如果您还过滤掉mx.*类,则会发现有871个UIComponent实例。每次创建UIComponent时,也会实例化一个Graphics对象。

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


1
去掉过滤后,提供了更多的信息。在运行分析器配置选项时,勾选“生成对象分配跟踪”选项。拍摄两个内存快照,选择两个,点击“查找悬垂对象”。使用分配跟踪来查看uiComponents何时被创建(在计时器滴答声上)-这指向正确的方向。 - Drenai
一会儿会发布如何找到确切罪犯的截图。 - Drenai

8

Flash Builder Profiler

  1. 使用Profiler运行应用程序(当询问时选择“生成对象分配跟踪”选项)
  2. 隔几秒钟拍摄两个内存快照
  3. 选择两个内存快照,然后单击“查找滞留对象”
  4. 确保单击筛选,并删除任何筛选器
  5. 按内存排序。UIComponent将在列表的顶部/接近顶部
  6. 在滞留对象窗口中双击UIComponent - 这会弹出对象引用窗口。
  7. 单击实例下的UIComponent并查看其分配跟踪,这将让您知道UIComponent创建的位置(如果您在分配跟踪视图上双击行号(此处为30),它将在源视图中打开该位置)。

现在你知道了内存问题的来源。

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

在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;
}

是的,比较内存快照功能通常会很有帮助。 - Florian F
我可能需要补充一点(否则我可能会错过什么)——步骤4必须在步骤2之前完成,否则快照将被过滤,并且不包含所有对象。 - Kricket

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接