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