除了渲染矢量图形外,AS3中主要的性能问题有哪些?

59
在ActionScript 3中,使用矢量图形是导致项目性能大幅下降的必然方式。
通过使用BitmapData对象上的.copyPixels()替换所有矢量图形,使用单个Bitmap来处理所有图像将获得荒谬的性能提升,并且对于像我这样在Flash中开发游戏的人来说至关重要。
除此之外,我不太确定下一个主要目标应该是什么,以及应该尝试优化什么。我确实使用了很多内置三角函数,但它们似乎并没有对性能产生太大影响。我知道有一些库使用近似方法等来优化数学计算,但到目前为止,我还没有发现这些是必要的。
还有其他需要注意的重要点吗?我更多地是指应该注意的内置事物(如避免矢量渲染),而不是如何改进自己的编码风格。
1个回答

126

我发现有用的文档包括:

一些亮点:

选择适当的显示对象

限制内存使用的最简单优化技巧之一是使用适当类型的 display object。对于不需要交互的简单形状,请使用 Shape 对象。对于不需要时间轴的 interactive objects,请使用 Sprite 对象。对于使用时间轴的动画,请使用 MovieClip 对象。

使用getSize()来对代码进行基准测试

getSize()返回指定对象在内存中的大小。

选择适当的基本类型以节省内存

除了String之外,所有原始类型在内存中使用4-8字节。 Number代表64位值,如果未分配值,则由ActionScript虚拟机(AVM)分配8个字节。 String类型的行为不同。通过基准测试代码并确定最有效的对象来完成任务。

重复使用对象

通过重复使用对象并尽可能避免重新创建对象来优化内存。

使用对象池

重复使用对象可以减少实例化对象的需求,这可能是代价高昂的。它还可以减少垃圾收集器运行的机会,从而减慢应用程序的速度。

空闲内存

为了确保一个对象被垃圾收集,删除所有引用该对象的内容。触发垃圾回收的是内存分配,而不是对象删除。尽可能地重复使用对象来减少垃圾回收次数。在可能的情况下将引用设置为null,以便垃圾收集器花费更少的处理时间来查找对象。将垃圾回收视为一种保险,并始终在可能的情况下明确管理对象生命周期。
将对显示对象的引用设置为null并不保证对象被冻结。对象将继续消耗CPU周期,直到进行垃圾回收。 BitmapData类包括一个dispose()方法,虽然dispose方法会从内存中删除像素,但必须仍将引用设置为null才能完全释放。

使用位图

使用矢量图形,特别是大量使用,会极大地增加 CPU 或 GPU 资源的需求。使用 位图 是优化渲染的好方法,因为运行时需要较少的处理资源来在屏幕上绘制像素,而不是渲染矢量内容。

避免使用滤镜,包括通过 Pixel Bender 处理的滤镜

当对显示对象应用滤镜时,运行时会在内存中创建两个位图。使用外部制作的位图有助于运行时减少 CPU 或 GPU 负载。

使用mipmapping缩放大图像

请谨慎使用mipmapping。虽然它可以提高缩小位图的质量,但会影响带宽、内存和速度。

使用Text Engine来显示只读文本,使用TextField来输入文本

对于只读文本,最好使用Flash Text Engine,它具有低内存使用和更好的渲染效果。对于输入文本,TextField对象是更好的选择,因为需要较少的ActionScript代码来创建典型的行为,例如输入处理和自动换行。 使用回调而不是事件 使用本地事件模型可能比使用传统回调函数更慢,消耗更多的内存。事件对象必须在内存中创建和分配,这会导致性能下降。例如,当监听Event.ENTER_FRAME事件时,每帧都会为事件处理程序创建一个新的事件对象。对于显示对象来说,性能可能会特别慢,因为捕获和冒泡阶段可能会很昂贵,如果显示列表很复杂。

在添加/删除舞台上冻结和解冻对象

即使显示对象不再在显示列表中,并等待垃圾回收,它们仍然可能使用CPU密集型代码。当使用Loader类加载远程内容时,冻结的概念也很重要。unloadAndStop()方法允许您卸载SWF文件,自动冻结加载的SWF文件中的每个对象,并强制运行垃圾收集器。

使用Event.ACTIVATEEvent.DEACTIVATE事件来检测后台不活动

Event.ACTIVATEEvent.DEACTIVATE事件可以帮助您检测运行时何时获得或失去焦点。因此,代码可以被优化以响应上下文变化。

激活和停用事件允许您实现类似于移动设备和Netbook上有时发现的“暂停和恢复”功能的机制。

尽可能禁用鼠标交互

检测鼠标交互可能会消耗大量CPU资源,特别是当许多交互对象显示在屏幕上时,尤其是它们重叠时。如果可能的话,请考虑禁用鼠标交互,这有助于减少应用程序的CPU处理量,从而降低移动设备的电池使用量。

对于非动画内容,请使用计时器

计时器比Event.ENTER_FRAME事件更适用于执行时间较长的非动画内容。
计时器可以像Event.ENTER_FRAME事件一样运作,但是事件可以在不绑定帧速率的情况下分派。这种行为可以提供一些显著的优化。以视频播放器应用程序为例。在这种情况下,您不需要使用高帧速率,因为只有应用程序控件在移动。

限制Tweening的使用

限制Tweening的使用,可以节省CPU处理、内存和电池寿命,帮助内容在低端设备上更快地运行。

使用Vector而不是Array

Vector 类允许比 Array 类更快的读写访问。与使用 Array 时相比,使用 Vector 实例进行数组元素访问和迭代要快得多。
在严格模式下,编译器可以识别数据类型错误。
运行时范围检查(或固定长度检查)明显提高了可靠性,超过了 Arrays。

使用绘图 API 实现更快的代码执行速度

使用drawPath(), drawGraphicsData(), drawTriangles()减少代码执行量,少写代码行可以提升ActionScript执行效率。

利用事件捕获和冒泡来最小化事件处理程序

利用事件冒泡可以帮助你优化ActionScript代码执行时间。你可以在一个对象上注册一个事件处理程序,而不是多个对象,以提高性能。

使用setVector()方法绘制像素

在绘制像素时,可以通过使用BitmapData类的适当方法来进行一些简单的优化。使用setVector()方法是快速绘制像素的一种方法。

在使用缓慢的方法如setPixel()setPixel32()时,务必锁定(lock())和解锁(unlock()BitmapData对象

调用 lock()unlock() 可以避免不必要地更新屏幕。针对像 getPixel(), getPixel32(), setPixel(), 和 setPixel32() 这些迭代像素的方法,在移动设备上可能会很慢。如果可能的话,使用可以一次检索所有像素的方法。对于读取像素,请使用 getVector() 方法,它比 getPixels() 方法更快。此外,尽可能使用依赖于 Vector 对象的 API,因为它们有望运行得更快。

使用String类方法代替正则表达式

如果String类方法可用,则比等效的正则表达式运行速度更快,并且不需要创建另一个对象。

对于TextFields,请使用apendText()而不是+=运算符

使用appendText()方法可以提高性能。

使用方括号运算符[]可能会降低性能 - 将引用存储在本地变量中

使用方括号运算符可能会降低性能。您可以通过将引用存储在本地变量中来避免使用它。

通过将代码移动到内联来减少函数调用次数

调用函数可能很昂贵。尝试通过将代码移动到内联来减少函数调用次数。

将函数调用移动到内联会导致代码快四倍以上。

避免将内容放置在舞台之外

即使舞台外的元素没有显示在屏幕上,也没有被渲染,它们仍然存在于显示列表中。运行时会继续对这些元素进行内部测试,以确保它们仍然处于舞台外且用户无法与其交互。

避免使用alpha属性

当显示对象使用alpha混合时,运行时必须结合每个堆叠的显示对象和背景颜色的颜色值来确定最终颜色。因此,Alpha混合可能比绘制不透明颜色更消耗处理器资源。这种额外的计算可能会影响性能较慢的设备。

使用尽可能低的帧率

高帧率比低帧率消耗更多的CPU周期和电池能量。

运行时代码执行基础知识 elastic-racetrack

对于复杂矢量内容,请使用位图缓存

以下是翻译内容:

此功能会缓存向量对象,将其在内部呈现为位图,并使用该位图进行渲染。如果缓存的内容未在每帧上旋转、缩放或更改,则位图缓存可提高渲染效果。除了在x轴和y轴上平移以外的任何变换都无法提高渲染质量。

在移动AIR应用中使用缓存的位图时,请设置cacheAsBitmapMatrix属性

在AIR移动配置文件中,您可以使用cacheAsBitmapMatrix对对象应用任何二维变换,而无需重新生成缓存的位图。您还可以在不重新生成缓存的位图的情况下更改alpha属性。

使用BitmapData类创建自定义位图缓存行为

只使用一个缓存的位图,以节省内存并由所有实例共享。

将事件(如Event.ENTER_FRAME)隔离在单个处理程序中

这种技术可以节省CPU资源。

使用位图缓存功能和opaqueBackground属性来提高文本渲染性能

位图缓存功能可将矢量内容缓存为位图以提高渲染性能。该功能对于复杂的矢量内容以及需要处理才能呈现的文本内容非常有帮助。

Alpha透明度会在绘制透明位图图像时给运行时增加额外负担。您可以使用opaqueBackground属性来绕过这一问题,通过指定一个颜色作为背景。

启用GPU硬件图形加速

为了在移动平台上利用Flash内容的GPU加速,Adobe建议您使用renderMode="direct"(即Stage3D),而不是renderMode="gpu"。Adobe正式支持和推荐以下基于Stage3D的框架:Starling(2D)Away3D(3D)
避免在HTML嵌入参数中使用wmode=transparent或wmode=opaque。这些模式可能会导致性能下降。它们还可能导致软件和硬件渲染中音视频同步的微小损失。此外,许多平台在这些模式生效时不支持GPU渲染,从而严重影响性能。

建议使用异步操作的版本

应用程序代码在当前执行线程中继续执行。

异步操作被安排和分割以避免渲染问题。因此,使用异步操作版本可以更轻松地拥有响应式应用程序。有关更多信息,请参见感知性能与实际性能

平滑形状以改善渲染

与位图不同,呈现矢量内容需要许多计算,特别是对于包含许多控制点的渐变和复杂路径。作为设计师或开发人员,请确保形状已经优化到足够好。

在加载资源后,将其本地缓存,而不是每次需要时从网络加载

如果您的应用程序加载媒体或数据等资源,请通过将它们保存到本地设备来缓存这些资源。对于不经常更改的资源,请考虑定期更新缓存。

使用StageVideo类利用硬件加速

使用StageVideo类以利用硬件加速来呈现视频。
这种方法充分利用了底层视频硬件。结果是CPU负载大大降低,这意味着在较弱的设备上帧率更高,同时内存使用也更少。

AAC音频格式在等效比特率下比mp3格式提供更好的质量和更小的文件大小

与视频解码类似,音频解码需要高CPU周期,并且可以通过利用设备上可用的硬件进行优化。
AAC格式在等效比特率下比mp3格式提供更好的质量和更小的文件大小。

尽量减少构造函数中的代码

初始化函数(如constructors)是解释执行的,其他所有内容都是JIT。


6
很棒的回答!+1。 我想补充一点,避免使用MouseEvent.MOUSE_MOVE(尤其是针对移动设备)。有一个简单的解决方法,就是立即从其处理程序中删除MOUSE_MOVE事件侦听器,基本上只调用它一次,然后将其传递给ENTER_FRAME事件处理程序。 - Chunky Chunk
关于enterframe事件 - 它可以静态分配,因为“只能有一个”(c) ,但是“消除”enterframe事件大多归结为减少显示列表的总大小,也就是blitting。关于计时器 - 它们可能会破坏实时游戏,因此应该非常小心地对待这个建议。我个人讨厌当计时器事件与基于帧的事件交织在一起,这样你触发了某些东西,它持续了一个计时器和/或引起代码延迟,并且它的效果通过帧事件可用,因此该东西的实际使用随机不定。 - Vesper
看起来构造函数中的代码实际上并不慢(即使它没有被JIT编译),基准测试:http://jacksondunstan.com/articles/276 和 https://konsnos.wordpress.com/2012/06/21/should-as3-constructor-be-lightweight/。 - fsbmain
@fsbmain - 深度继承链、大量实例化/内存分配更能生动地展现出其影响。第一篇文章测试结果不正确;第二篇文章表明构造函数较慢。 - Jason Sturges
根据我的经验,Alpha非常占用CPU资源,而且我发现将复杂向量渲染到高分辨率(如4K屏幕)上会带来很多麻烦。 - Mar

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