Flex 分析 - [enterFrameEvent] 在做什么?

发布于 2024-07-09 14:07:32 字数 810 浏览 5 评论 0原文

我的任务是查找(并可能修复)交付给我们的 Flex 应用程序的一些严重性能问题。 当应用程序只是闲置并且不应该执行任何操作时,它有时会持续占用 50% 到 100% 的 CPU。

我的第一步是运行 FlexBuilder 附带的分析器。 我希望找到一些占用大部分时间的方法,告诉我瓶颈在哪里。 然而,我得到了一些意想不到的事情。

前 4 个方法是:

  • [enterFrameEvent] - 84% 累积,32% 自时间
  • [reap] - 20% 累积和自时间
  • [tincan] - 8% 累积和自时间
  • global.isNaN - 4% 累积和自时间

所有其他方法的累积时间和自我时间均小于 1%。

根据我在网上找到的内容,[括号内的方法]是探查器在没有实际的 Flex 方法可显示时列出的内容。 我看到有人声称[tincan]是RTMP请求的处理,我假设[reap]是垃圾收集器。

有谁知道 [enterFrameEvent] 实际上在做什么? 我认为它本质上是事件循环的“主要”函数,因此预计会有较高的累积时间。 但为什么自拍时间这么长呢? 究竟发生了什么? 我没想到播放器内部会占用这么多时间,特别是因为应用程序中实际上没有发生任何事情(并且没有进行 UI 更新)。

有什么好的方法可以深入了解正在发生的事情吗? 我知道发生了一些不应该发生的事情(看起来一定存在某种繁忙等待或其他失控循环),但探查器没有给我任何我期望的结果。 我的下一步将是开始在不同的地方添加调试跟踪语句,以尝试跟踪实际发生的情况,但我觉得必须有更好的方法。

I've been tasked with finding (and potentially fixing) some serious performance problems with a Flex application that was delivered to us. The application will consistently take up 50 to 100% of the CPU at times when it is simply idling and shouldn't be doing anything.

My first step was to run the profiler that comes with FlexBuilder. I expected to find some method that was taking up most of the time, showing me where the bottleneck was. However, I got something unexpected.

The top 4 methods were:

  • [enterFrameEvent] - 84% cumulative, 32% self time
  • [reap] - 20% cumulative and self time
  • [tincan] - 8% cumulative and self time
  • global.isNaN - 4% cumulative and self time

All other methods had less than 1% for both cumulative and self time.

From what I've found online, the [bracketed methods] are what the profiler lists when it doesn't have an actual Flex method to show. I saw someone claim that [tincan] is the processing of RTMP requests, and I assume [reap] is the garbage collector.

Does anyone know what [enterFrameEvent] is actually doing? I assume it's essentially the "main" function for the event loop, so the high cumulative time is expected. But why is the self time so high? What's actually going on? I didn't expect the player internals to be taking up so much time, especially since nothing is actually happening in the app (and there are no UI updates going on).

Is there any good way to find dig into what's happening? I know something is going on that shouldn't be (it looks like there must be some kind of busy wait or other runaway loop), but the profiler isn't giving me any results that I was expecting. My next step is going to be to start adding debug trace statements in various places to try and track down what's actually happening, but I feel like there has to be a better way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

波浪屿的海角声 2024-07-16 14:07:32

Flex 项目中的 EnterFrame 处理程序上通常会发生一些事情。 一些需要注意的事情

  1. 手册< mycomponent EnterFrame="" > 事件响应或通过 component.addEventListener(Event.ENTER_FRAME, myfunc) 手动添加的响应

  2. callLater() 调用手动添加的响应,这些在框架中发生很多,并且可能是跳入任意数量的兔子洞的副产品,开发人员倾向于大量使用这些解决与时序相关的问题,有时错误的代码可能会导致它们继续调用每一帧。 例如,在最新的 flex sdk 版本中大约出现了 120 次 calllater()。

  3. 最后,我不能保证 [enterframeEvent] 只处理 EnterFrame 特定的事件回调,而不处理计时器、鼠标等事件,因为 EnterFrame 发生在主事件循环期间,您可能会看到以下的累积结果从主事件池触发的所有事件。 我并不是说这就是正在发生的事情,但我也不能说这不是正在发生的事情,我对内部结构了解不够,无法确定。

/edit 也如前所述,[enterFrameEvent] 从技术上讲应该在每帧开始时在内部触发,但它不应该执行任何操作,除非事件已显式附加到它以执行用户代码。

Theres a couple things that typically happen on an enterframe Handler within a flex project. Some things to watch for

  1. Manual < mycomponent enterFrame="" > event responses or ones added manually via component.addEventListener(Event.ENTER_FRAME, myfunc)

  2. callLater() calls, these happen ALOT in the framework and can be byproduct of jumping down any number of rabbit holes, developers tend to use these alot to solve timing related problems and sometimes bad code can cause these to continue calling every frame. For example, there are ~120 occurrences of a calllater() in the latest flex sdk build.

  3. lastly, I can't guarantee that the [enterframeEvent] handles just enterframe specific event callbacks, and not timers, mouse, etc.. events, since enterframes occur during the main event loop, you may be seeing the cumulative result of all events firing from the main event pool. I'm not saying this IS whats happening, but I can't say it ISN'T whats happening either, I don't know enough about the internals there to be sure.

/edit also as stated earlier, the [enterFrameEvent] should technically fire internally at the start of each frame, but it shouldn't be doing anything unless events have been explicitly attached to it to execute user code.

牵强ㄟ 2024-07-16 14:07:32

一些更新:
除了监听事件和使用绑定之外,我们没有在应用程序中执行任何操作...也就是说,没有 ChangeWatchers,没有手动轮询...只是等待事件。 我们始终连接到 FMS,因此会产生一些开销,但很小。 Flex 中的绑定并不是非常高效,而且我们发现将 [Bindable] 元数据关键字直接添加到类中(数量很大,有很多类)并不好。 我们在这方面做得不多,但这是提高应用程序性能的一种方法。 如果您使用 [Bindable(event="usersUpdated")] 那么您可以控制绑定,并且只有当您从类中的函数中调度Event(new Event("usersUpdated")) 时才会触发,即您的“用户”的设置者。

任何在 Flex 或 AIR 中使用过 System.gc() 的人都会告诉您 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;

前者对绑定到 location.* 的任何内容触发 3 个绑定,而后者应该只触发 1 个绑定(实际上,由于 Flex 处理它的方式,这通常是额外的。)

除非您有很多绑定,否则绑定不会杀死您的应用程序在视觉效果丰富的应用程序中......绑定和渲染似乎是 Flex 最慢的工作。

另一个有趣的事情是:在 Flex Builder 中创建一个全新的 Flex3 应用程序并在浏览器中运行它。 我们的测试表明,MacBookPro 上的 CPU 保持在 8-10% 之间(当应用程序空闲且浏览器窗口隐藏时)。 我们的应用程序现在稳定地运行在约 20% 的水平上,虽然为了处理视图更改等而飙升得更高,但它总是返回到接近 20% 的水平。 我们最初担心的是存在内存泄漏或某些失控的情况,这会导致 CPU 占用率非常高,并使其徘徊在 40-50% 左右(同样,在 MBP 上……所有这些都与本机相关)。 我们删除了所有对 Degrafa 的引用,虽然我们注意到性能有了很大的提高,但它并不能说明一切。 不过,空的 Flex 应用程序很有启发性 - Flex 本身始终占用 8-10% 的 CPU,即使在空闲时也是如此。

另一个发现...如果使用 Mate,请注意如何处理切换视图。 通过使用 MXML 中的注入器和绑定,可以轻松地获得可用资源,并在不使用它们时隐藏和禁用它们,但 Flex 在隐藏/禁用事物方面并不是很聪明。 最好即时创建视图,并在完成后销毁它们。 尽管初始创建可能需要更多时间并且视图之间的等待时间更长,但请使用一些显示魔法(进度条、旋转磁盘等)来指示视图正在切换,等待视图上的创建完成,然后淡入其中。

另外,对于视觉效果丰富的应用程序,请远离 ViewStack。 管理您自己的堆栈。

到目前为止,这个线程已经讨论了任何语言都常见的基本性能问题,但 Flex 在很多方面都是一个非常特别的小男孩(“特别”并不总是被认为是积极的事情)。 有无数的陷阱,因为它构建在一个非常可视化的平台上,但它是为 RIA 构建的,因此虽然 Flash Player 可以优化视频、动画等,但它不会优化 Flex 应用程序。 不要期望 Flex 应用程序的性能与 Flash 应用程序相同。 AS2 和 AS3 的 AVM(ActionScript 虚拟机)之间也存在很大差异。

这只是触及了 Flex 应用程序的性能问题和潜在收益的表面。 这是一门黑暗艺术,原因很容易理解。

忍者们,编码吧。

Some updates:
We aren't doing anything in the app other than listening for events and using bindings...meaning, no ChangeWatchers, no manual polling...just waiting for events. We are connected to FMS the entire time, so there is some overhead for that, but it's minimal. Bindings are not super efficient in Flex, and we've found that it's not good to add the [Bindable] metadata keyword directly to classes (in high volume, with a lot of classes). We aren't doing much of this, but it's one way to squeeze a bit more performance out of your app. If you use the [Bindable(event="usersUpdated")] then you have control over the binding, and it will only fire when you dispatchEvent(new Event("usersUpdated")) from within a function in the class, ie, your setter for 'users'.

Anyone who's used System.gc() in Flex or AIR will tell you that Flex garbage collection is a joke. It is a partially implemented feature and no one trusts it. There are tricks for this too...call it twice, wait a frame, call it again. It might clean up your old objects, but don't cross your fingers...Flex does what it wants.

Also, use temporary objects to decrease the number of bindings fired. Instead of...

myUser.location = new Location();
myUser.location.state = "CO";
myUser.location.city = "Denver";

do...

var tempLoc : Location = new Location();
tempLoc.state = "CO";
tempLoc.city = "Denver";
myUser.location = tempLoc;

The former fires 3 bindings to anything bound to location.*, while the latter should only fire 1 binding (in reality it's usually extra due to the way Flex handles it.)

Bindings won't kill your app until you have a lot of them in a visually rich application....binding and rendering seem to be Flex's slowest jobs.

Another interesting thing: create a brand new Flex3 app in Flex Builder and run it in the browser. Our tests showed that the CPU stays between 8-10% on a MacBookPro (when the app is idle, and the browser window hidden). Our application now runs steadily at ~20% and while it spikes higher in order to handle view changes and the like, it always returns to a level close to 20%. Our initial concern was that there was a memory leak or something running away that would take the CPU very high and leave it hovering around 40-50% (again, on the MBP...all relative to this machine). We took out all references to Degrafa and while we noticed a good bit of performance increase, it didn't account for everything. The empty Flex app was enlightening though - Flex itself hogs 8-10% CPU at all times, even when idle.

Yet another find...if using Mate, be careful how you handle switching views. It's easy to have assets available and just hide&disable them when they're not being used, by using an injector and a binding in MXML, but Flex is not very smart when it comes to hiding/disabling things. It's best to create the views on the fly, and destroy them when they are done. Even though the initial creation may take more time and there will be a longer wait between views, use some display magic (a progress bar, spinning disk, etc) to indicate that the view is switching, wait for creationComplete on the view, and then fade into it.

Also, stay away from ViewStack for visually rich apps. Manage your own stack.

So far this thread has gone over basic performance issues common to any language, but Flex is a very special little boy in many ways ("special" not always considered a positive thing). There are innumerable pitfalls because it's built on a very visual platform, yet it's built for RIAs, so while Flash Player may optimize video, animations, etc, it won't optimize a Flex app. Do not expect Flex apps to perform the same as Flash apps. There is also a big difference between AVM (ActionScript Virtual Machine) for AS2 and AS3.

This is simply scratching the surface of performance issues and potential gains in Flex apps. This is a dark art and it's easy to see why.

Code on, ninjas.

路还长,别太狂 2024-07-16 14:07:32

如果将来有人遇到这个问题,请对这篇文章进行更新...

几个月后,EffectiveUI 的一些同事在他们的应用程序中遇到了这个确切的问题,因此重新审视了它。 人们发现,当使用 Flash 生成视觉资源、使用 STATEFUL SKINS 并使用 Flash/Flex 资源工具包将它们导出到 SWC 时,您会得到失控的 Flash 影片(大概是其实现方式的内部原因,例如,忘记将帧中的 stop() 命令)。

显然,除了进去并删除所有有状态的皮肤之外,你对此无能为力。 可以在这里找到一篇很好的文章:

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

以及一个 JSFL 脚本,您可以用于将有状态皮肤转换为无状态皮肤:

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

希望这对某人有帮助! 这是一个非常令人讨厌、神秘的错误,但你可以解决它!

干杯

An update to this post should anyone come across it in the future...

A few coworkers at EffectiveUI had this exact problem with their application a couple of months later, so it was revisited. It was discovered that when using Flash to produce visual assets, USING STATEFUL SKINS, and exporting them to SWC with the Flash/Flex asset toolkit, you get runaway Flash movies (presumably something internal to the way this is implemented, say, forgetting to put stop() commands in frames).

There is apparently nothing you can do about it except to go in and remove all stateful skins. A good write-up can be found here:

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

And a JSFL script that you can use to convert stateful skins to stateless skins:

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

Hope this helps someone! It's a very nasty, mysterious bug, but you can work around it!

Cheers

眼趣 2024-07-16 14:07:32

我认为你的问题出在其他地方。 发生这种情况是因为 Flex 构建在 Flash 之上,并且 Flash 触发该事件的频率与帧速率相同(例如每秒 20-30 次)。

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

编辑:我并不是说你的解决方案是降低帧速率。 仅当您注意到的事件是问题所在时,这才有效。 我不相信这实际上是导致你的速度变慢的原因。 可能是调用某个函数导致了问题......但该事件本身并不是问题。 应该会火很多

I think your problem lies elsewhere. This happens because Flex is built on top of Flash and Flash fires that event as often as the framerate (so like 20-30 times a second).

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

EDIT: I'm not saying your solution would be to lower the framerate. That would only work if the event u noticed were the issue. I'm not convinced that that is actually what's causing your slowdowns. It may be the calling a function that is causing the issue... but that event itself isn't it. It's supposed to fire a lot.

空‖城人不在 2024-07-16 14:07:32

此链接解释了性能分析器中描述的每个[功能]:

http://livedocs.adobe.com/flex/gumbo/html/WS6f97d7caa66ef6eb1e63e3d11b6c4d0d21-7edf.html

This link explains each of the [function]'s described in the performance profiler:

http://livedocs.adobe.com/flex/gumbo/html/WS6f97d7caa66ef6eb1e63e3d11b6c4d0d21-7edf.html

久随 2024-07-16 14:07:32

贾斯汀,谢谢你的回复。
问题不在于 EnterFrame 执行,而在于它在每次迭代中尝试执行太多操作。

仅供参考:巧合的是,原发帖者和我正在处理同一个应用程序。 我们决定删除所有 Degrafa 资源,转而使用 ProgrammaticSkins。 当我们完成这项工作后,我将在这里报告调查结果。

Justin, thanks for the reply.
The issue is not with enterFrame executing, but rather with it trying to do too much in each iteration.

FYI: Coincidentally, the original poster and I are dealing with the same application. We have decided to remove all Degrafa resources in favor of ProgrammaticSkins. I'll report the findings here when we have completed this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文