Профилирование Flex - что делает [enterFrameEvent]?

Мне было поручено найти (и потенциально исправлять) некоторые серьезные проблемы с производительностью с помощью приложения Flex, которое было доставлено нам. Приложение будет постоянно занимать от 50 до 100% процессора в моменты, когда он просто работает на холостом ходу и ничего не должен делать.

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

Лучшие 4 метода:

  • [enterFrameEvent] - 84% накопленного времени, 32% времени
  • [reap] - 20% кумулятивное и самостоятельное время
  • [tincan] - 8% кумулятивного и самостоятельного времени
  • global.isNaN - 4% кумулятивное и собственное время

Все остальные методы имели менее 1% как для кумулятивного, так и для собственного времени.

Из того, что я нашел в Интернете, методы [скобки] - это то, что списки профилировщиков, когда у него нет фактического метода Flex для отображения. Я заметил, что кто-то утверждает, что [tincan] - обработка запросов RTMP, и я предполагаю, что [reap] - сборщик мусора.

Кто-нибудь знает, что делает [enterFrameEvent] на самом деле? Я предполагаю, что это, по сути, "основная" функция для цикла событий, поэтому ожидается высокое суммарное время. Но почему самооценка так высока? Что на самом деле происходит? Я не ожидал, что внутренняя часть проигрывателя будет занимать столько времени, тем более, что в приложении ничего не происходит (и обновлений обновления пользовательского интерфейса не происходит).

Есть ли какой-нибудь хороший способ найти, что происходит? Я знаю, что что-то происходит, это не должно быть (похоже, должно быть какое-то занятое ожидание или другой цикл бегства), но профилировщик не дает мне никаких результатов, которых я ожидал. Следующим шагом будет добавление операторов отладки трассировки в разных местах, чтобы попытаться отследить, что на самом деле происходит, но я чувствую, что должен быть лучший способ.

Ответы

Ответ 1

Это пара вещей, которые обычно происходят в обработчике ввода в рамках проекта flex. Некоторые вещи для просмотра

  • mycomponent enterFrame = "" > ответы на события или те, которые добавлены вручную через component.addEventListener(Event.ENTER_FRAME, myfunc)

  • вызовы callLater(), они происходят в структуре и могут быть побочным продуктом спрыгивания любого количества кроличьих дыр, разработчики, как правило, используют эти много для решения проблем, связанных с временем, а иногда и с плохим кодом, что может привести к их продолжению вызов каждого кадра. Например, в последней версии flex sdk существует ~ 120 вхождений calllater().

  • Наконец, я не могу гарантировать, что [enterframeEvent] обрабатывает только входящие вызовы специальных событий, а не таймеры, мышь и т.д. события, так как enterframes происходят во время цикла основного события, вы можете видеть совокупный результат всех событий, запускаемых из основного пула событий. Я не говорю, что это происходит, но я не могу сказать, что это НЕ то, что происходит, я не знаю достаточно о внутренних там, чтобы быть уверенным.

/edit также, как указано ранее, [enterFrameEvent] должен технически запускаться внутри системы в начале каждого кадра, но он ничего не должен делать, если события не были явно привязаны к нему для выполнения кода пользователя.

Ответ 2

Некоторые обновления: Мы ничего не делаем в приложении, кроме прослушивания событий и использования привязок... что означает, не ChangeWatchers, никаких ручных опросов... просто жду событий. Мы все время подключаемся к FMS, поэтому для этого есть некоторые накладные расходы, но они минимальны. Привязки не суперэффективны в Flex, и мы обнаружили, что не очень удобно добавлять ключевое слово [Bindable] метаданных непосредственно в классы (в большом объеме, с большим количеством классов). Мы мало что делаем, но это один из способов сжать немного больше производительности вашего приложения. Если вы используете [Bindable (event = "usersUpdated" )], тогда у вас есть контроль над привязкой, и он будет срабатывать только тогда, когда вы dispatchEvent (новое событие ( "usersUpdated" )) из функции в классе, т.е. Ваш setter для "пользователей".

Любой, кто использовал System.gc() в Flex или AIR, скажет вам, что сборка мусора Flex - это шутка. Это частично реализованная функция, и никто не доверяет ей. Для этого есть трюки... вызовите его дважды, подождите фрейм, вызовите его снова. Он может очистить ваши старые объекты, но не пересекать пальцы... Flex делает то, что он хочет.

Кроме того, используйте временные объекты, чтобы уменьшить количество привязок. Вместо...

myUser.location = new Location(); myUser.location.state = "CO"; myUser.location.city = "Денвер";

делать...

var tempLoc: Location = new Location(); tempLoc.state = "CO"; tempLoc.city = "Денвер"; myUser.location = tempLoc;

Бывший загорается 3 привязки к чему-либо, связанному с местоположением. *, в то время как последний должен только активировать 1 привязку (на самом деле это обычно дополнительно из-за того, как Flex обрабатывает его.)

Привязки не будут убивать ваше приложение, пока у вас их не будет много в визуально богатом приложении.... привязка и рендеринг кажутся самыми медленными заданиями Flex.

Еще одна интересная вещь: создайте новое приложение Flex3 в Flex Builder и запустите его в браузере. Наши тесты показали, что процессор остается на уровне 8-10% на MacBookPro (когда приложение простаивает, а окно браузера скрыто). Наше приложение теперь работает стабильно на уровне ~ 20%, а пока оно шипнее для обработки изменений вида и т.п., оно всегда возвращается к уровню, близкому к 20%. Наша первоначальная проблема заключалась в том, что произошла утечка памяти или что-то ускользающее, что очень сильно повлияло бы на процессор и опустилось бы на 40-50% (опять же, на MBP... все относительно этой машины). Мы вытащили все ссылки на Degrafa, и пока мы заметили хороший рост производительности, он не учитывал все. Пустое приложение Flex было просвещенным, хотя - сам Flex сам забирает 8-10% процессора во все времена, даже когда он работает.

Еще одна находка... если вы используете Mate, будьте осторожны, как вы обрабатываете переключение просмотров. Легко иметь доступные активы и просто скрывать и отключать их, когда они не используются, используя инжектор и привязку в MXML, но Flex не очень умна, когда дело доходит до скрытия/отключения. Лучше всего создавать взгляды "на лету" и уничтожать их, когда они будут сделаны. Несмотря на то, что для первоначального создания может потребоваться больше времени, и между просмотрами будет более длинное ожидание, используйте некоторую манеру отображения (индикатор выполнения, вращающийся диск и т.д.), Чтобы указать, что просмотр переключается, ждать созданияComplete на представлении, а затем впасть в него.

Кроме того, держитесь подальше от ViewStack для визуально богатых приложений. Управляйте собственным стеком.

До сих пор эта тема затрагивала основные проблемы производительности, общие для любого языка, но Flex - очень особенный маленький мальчик во многих отношениях ( "особенный" не всегда считается позитивным). Есть бесчисленные ловушки, потому что он построен на очень визуальной платформе, но он построен для RIA, поэтому, хотя Flash Player может оптимизировать видео, анимацию и т.д., Он не будет оптимизировать приложение Flex. Не ожидайте, что приложения Flex будут работать так же, как и Flash-приложения. Существует также большая разница между AVM (ActionScript Virtual Machine) для AS2 и AS3.

Это просто царапает поверхность проблем с производительностью и потенциальную выгоду в приложениях Flex. Это темное искусство, и легко понять, почему.

Код, ниндзя.

Ответ 3

Обновление этого сообщения должно появиться в будущем...

Несколько сотрудников в EffectiveUI столкнулись с этой проблемой с их применением через пару месяцев, поэтому она была пересмотрена. Было обнаружено, что при использовании Flash для создания визуальных активов, ИСПОЛЬЗУЯ ПОСТОЯННЫЕ КОЖИ и экспортируя их в SWC с помощью инструментария Flash/Flex, вы получаете безупречные флеш-ролики (по-видимому, что-то внутреннее по отношению к тому, как это реализовано, скажем, забывая положить stop() в кадрах).

Похоже, вы ничего не можете с этим поделать, кроме как войти и удалить все шкуры состояния. Хорошую запись можно найти здесь:

http://patrickhansen.com/blog/index.php/2009/03/05/flex-stateful-skins-vs-stateless?blog=3

И JSFL script, который вы можете использовать для конвертирования скинов с сохранением состояния в скины без сохранения:

http://patrickhansen.com/blog/index.php/2009/04/08/stateful-to-stateless-jsfl-flash-command?blog=3

Надеюсь, это поможет кому-то! Это очень неприятная, загадочная ошибка, но вы можете обойти ее!

Приветствия

Ответ 4

Я думаю, ваша проблема кроется в другом месте. Это происходит потому, что Flex построен поверх Flash и Flash запускает это событие так часто, как частота кадров (так же, как 20-30 раз в секунду).

http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/actionscript_dictionary546.html

EDIT: Я не говорю, что ваше решение было бы снизить частоту кадров. Это будет работать, только если событие, которое вы заметили, было проблемой. Я не уверен, что это на самом деле то, что вызывает замедление. Это может быть вызов функции, которая вызывает проблему... но это событие само по себе не так. Он должен много стрелять.

Ответ 7

Джастин, спасибо за ответ. Проблема заключается не в выполнении enterFrame, а в попытке сделать слишком много на каждой итерации.

FYI: Кстати, оригинальный плакат и я имеем дело с одним и тем же приложением. Мы решили удалить все ресурсы Degrafa в пользу ProgrammaticSkins. Я сообщу результаты здесь, когда мы это завершим.