Flash Builder 4 Профилировщик: как определить, какие объекты вызывают известное увеличение памяти?

Я знаю, что вопросы профилирования могут быть довольно общими, но здесь у меня есть очень конкретный вопрос и пример.

Я знаю, что в следующем коде (взятом из вопрос Джошуа), что в 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>

Ответ 1

Во-первых, я посмотрю на панель "Использование памяти", немного поиграв с приложением:

enter image description here

Обратите внимание, что память увеличивается все больше и больше. Существует кнопка "Запустить сборщик мусора", которая заставляет GC. Однако, когда вы нажимаете на нее, память не уменьшается.

Следующий шаг - выявить виновных. Для этого вы используете панель "Живые объекты":

enter image description here

Похоже на то, что некоторые векторные экземпляры, все выглядит хорошо. По умолчанию, многие классы фильтруются из datagrid живых объектов. К счастью, можно указать, какие классы будут отображаться и скрываться. Все классы из пакетов flash.x.x по умолчанию скрыты. Удаление их из отфильтрованного списка приводит к чему-то интересному в таблице:

enter image description here

Обратите внимание на строку Graphics: создано 871 экземпляр, и все они все еще в памяти! С этой информацией вы можете предположить, что экземпляры Graphics несут ответственность за замедление работы приложения. Если вы также отфильтровываете классы mx. *, Вы увидите, что есть 871 экземпляр UIComponents. Каждый раз, когда создается UIComponent, существует также объект Graphics.

Заключительный шаг - удалить каждый UIComponent, если он больше не нужен на экране, и посмотрите, есть ли улучшение производительности.

Ответ 2

Flash Builder Profiler

  • Запустите приложение с помощью Profiler (выберите опцию "Создать трассировку распределения объектов", если задано)
  • Возьмите два моментальных снимка памяти за несколько секунд.
  • Выберите оба моментальных снимка Memeory и нажмите "Найти объекты Loitering".
  • Обязательно нажмите "Фильтрация" и удалите все фильтры.
  • Сортировать по памяти. UIComponent будет сверху/ближе к началу списка.
  • Дважды щелкните UIComponent в окне Loitering Objects - это вызывает окно "Ссылки на объекты".
  • Щелкните UIComponent в разделе "Экземпляры" и просмотрите его трассировку выделения, это даст вам знать где этот UIComponent был создан (если вы дважды щелкните по экрану Allocation Trace, где он дает вам номер строки - 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;
}