随着时间的推移,AS3大型游戏性能下降

9

我目前正在开发一款非常庞大的Flash平台游戏(数百个类),面临一个问题:如果长时间运行游戏,则游戏会逐渐变慢。由于我没有编写游戏,因此我对其内部只有一些模糊的了解。其中一些神秘的症状包括:

  • 游戏在给定的关卡上运行良好一段时间后,突然开始呈指数级泄漏内存。
  • 当屏幕上有更多精灵时,游戏达到指数级泄漏的时间会更短。
  • 即使屏幕上没有可见的渲染物,游戏也会变慢。
  • 精灵碰撞越频繁,游戏速度下降得就越快。
  • 完全禁用碰撞代码确实减缓了性能下降的速度,但无法阻止游戏最终掉帧。

查看源代码并使用Flex分析器,我的主要嫌疑对象是:

  • 存在许多游离对象,特别是WeakMethodClosure,占用了大量内存。
  • 程序极度广泛地使用弱事件侦听器(每帧分派数十个)。
  • 每次创建新精灵时都会复制BitmapData。这些是50x50像素的精灵,每秒产生约8个。

我知道没有看到源代码几乎不可能告诉我问题所在,因此我只是寻找可能有助于我缩小范围的细节。是否有人在自己的项目中遇到了这种难以捉摸的性能下降?你的情况是什么原因导致的呢?

7个回答

7

我最近完成了一个大型项目的优化。

以下是一些架构建议:

  1. 主要原则-尽量少调用函数/事件
  2. 除了一个onEnterFrame/onInterval/onTimer循环外,摆脱所有其他循环。在一个总体事件调用中完成所有需要的操作。您可能需要许多静态数组来存储已处理的对象引用。
  3. 一个主循环中执行图形/渲染操作
  4. 尝试使用大型(可能是预渲染的)画布,而不是小型精灵/位图。通常可用于背景。但也适用于较小的对象(如树木、平台等)
  5. 摆脱小位图资源,将其组合成一个瓷砖表,并直接通过source-rect属性绘制您的内容

希望这对您有所帮助!内存泄漏真是个头痛的问题。

P.S. 在不同的浏览器中测试您的游戏,IE是最容易出现泄漏的浏览器,有时刷新后它不会清除内存。


我认为这是一个非常好的建议,特别适用于那些刚开始进行大型游戏项目并想知道如何最好地构建它的人。 - Kai

3
  • 避免使用匿名方法 - 将它们改为类级别的方法。
  • 在 addEventListener 中使用弱引用和/或确保在使用 removeChild 删除对象之前移除所有侦听器。
  • 确保删除所有精灵而不仅仅是让它们飞出屏幕。此外,如果可能的话,请重复使用精灵而不是创建新的。

1
如果您需要频繁地创建/销毁大型对象(如BitmapData),特别是在数量较多的情况下,建议考虑使用对象池技术。
请参见Object Pool class

一旦我确定是哪些资源导致了瓶颈,这个想法就非常好。 - Kai

0

听起来你需要对应用程序进行分析以查看发生了什么。

这个线程提供了一些建议,但最终,您需要编写代码来帮助确定发生了什么。

分析ActionScript-3代码

您可能想要查看是否可以在一段时间内运行一些较小的部分并查看是否会出现减速。

您可能希望对应用程序进行单元测试,以便可以快速运行各种部分,寻找内存泄漏。一个框架是:http://asunit.org/,另一个是:http://opensource.adobe.com/wiki/display/flexunit/

单元测试是我用于分析的重要工具,因此您可以在游戏的顶层进行测试,运行数千次,寻找问题,然后运行每个部分并查看哪个部分有问题,然后逐步解决。这是一个手动过程,但如果SO线程开头列出的两个想法没有帮助,那么这可能是您最好的方法。

你的内存使用太多了吗?还是你的 CPU 使用率过高?


问题提到了内存泄漏,所以我猜测 CPU 使用率不是问题。 - David Locke
我正在尝试查看除了他猜测的问题之外是否还有其他问题。不幸的是,当我猜测我的程序存在问题时,我往往是错误的,这就是为什么我如此依赖性能分析的原因。 - James Black
我在想,过度的垃圾回收是否会导致程序的退化,因为太多的对象被快速生成。 - James Black

0
首先确定是内存限制还是处理器限制。听起来像是后者,似乎有很多对象在做一些事情......可能那些额外的精灵没有被很好地释放。查找对象/变量/事件中的任何依赖项,请确保删除精灵,注意EnterFrame或重复事件的任何处理程序。

0

听起来更可能是处理器速度达到了极限,而不是内存。你必须尽力才能使Flash应用程序达到内存上限。

幸运的是,有很多简单的事情可以做来降低CPU使用率...

1)严格管理所有事件侦听器,特别是鼠标侦听器。您的精灵对象上是否有$texas事件侦听器?这可能是个问题。

2)使用int或uint访问数组,而不是Number。这非常重要,也是那些偏门的Adobe技巧之一。使用int和uint访问数组对象比Number快得多,如果您进行大量迭代(听起来您确实这样做了),这可以从帧执行中削减宝贵的毫秒数。

3)与#2相同,监视您的数学运算以及您在某些运算中使用的类型。在AS3中进行数学运算最慢的事情是重复强制转换(将int提供给返回Number的函数),或者在Number上执行基本操作(如加法和减法)而不是int。

在Flash中拥有一个像这样庞大的程序的好处是,即使是微小的优化变化也可能对性能产生重大影响。我曾经在AS3中玩过一个光线跟踪引擎,我声明了一个额外的变量,它将我的FPS从30降到了23。


我相信我的游戏在至少几个地方违反了这些规则。希望问题不是太大! - Kai

0
Flash有一个相当臭名昭著的问题(许多人认为它是一个bug),即使它们被弱引用,也会导致计时器和ENTER_FRAME事件的事件侦听器无法进行垃圾回收。因此,即使使用弱引用事件是一个好习惯,但在不再需要它们时仍应删除所有事件侦听器。

经过快速搜索Event.ENTER_FRAME,我找到了18个匹配项,因此可以肯定问题也可能出在这里。 - Kai

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