Apache flex 不变性和Flex是一个糟糕的组合吗?
在我的scratch构建的flex游戏框架中,我定义了一个名为ThreeDPoint的类,它携带一个x、y和z坐标集来跟踪游戏中的对象,称为Actors。我还使用该类创建运动向量,这些向量在每一帧中叠加在一起,为每个参与者创建一个累积的运动向量 我将ThreeDPoint类设置为不可变类,以支持以下观点:给定的位置无法更改,您只能给演员一个新的位置,同时也阻止潜在的客户端程序员(我!)更改堆栈中的运动向量,而不是分配一个新的运动向量来创建您想要的运动类型 不幸的是,这个系统的性能下降得非常快。使用Flex Builder profiler,我注意到我泄漏了一些三点对象(我有26个参与者,大概有30个,但只要60秒的运行时间,我就有1000多个这样的对象),但由于这些对象非常轻量级,实际内存占用相当稳定 另一方面,分析器显示在运行60秒后累计创建的250000多个三点对象。现在,由于我是如何故意创造和扔掉这些东西的,这对我来说一点也不奇怪。但是当看到这样一个概要文件时,我想到的唯一一件事是大量的new()和GC调用(不,我没有显式地调用GC)是影响性能的因素,特别是考虑到这样一个事实,即当我开始时,三点是可变的,一切都很好。这似乎合理吗Apache flex 不变性和Flex是一个糟糕的组合吗?,apache-flex,actionscript-3,immutability,Apache Flex,Actionscript 3,Immutability,在我的scratch构建的flex游戏框架中,我定义了一个名为ThreeDPoint的类,它携带一个x、y和z坐标集来跟踪游戏中的对象,称为Actors。我还使用该类创建运动向量,这些向量在每一帧中叠加在一起,为每个参与者创建一个累积的运动向量 我将ThreeDPoint类设置为不可变类,以支持以下观点:给定的位置无法更改,您只能给演员一个新的位置,同时也阻止潜在的客户端程序员(我!)更改堆栈中的运动向量,而不是分配一个新的运动向量来创建您想要的运动类型 不幸的是,这个系统的性能下降得非常快。使
package net.emptykingdom.utils
{
public class ThreeDPoint
{
public function ThreeDPoint(x:Number = 0, y:Number = 0, z:Number = 0)
{
this._x = x;
this._y = y;
this._z = z;
}
public function get X():Number { return _x; }
public function get Y():Number { return _y; }
public function get Z():Number { return _z; }
private var _x:Number = 0;
private var _y:Number = 0;
private var _z:Number = 0;
}
}
编辑:我已找到并删除内存泄漏。它带来了一个很小但很明显的性能增益,尽管还没有大到可以实例化大量参与者的程度。根据分析器,我的代码仍然由对三点构造函数的调用控制。回到一个可变的三分球让我找回了我曾经享受过的相当多的表现。因此,我猜Flex对象实例化比我在其中玩过的其他环境更昂贵。太糟糕了。我想说,在AS3的性能敏感应用程序中,使用不可变值来表示快速变化的值是一个糟糕的组合,是的。AS3不是最快的环境,让它处理3D意味着压缩性能。要求它为原语值的每次更改创建一个新对象可能会带来麻烦。您的描述非常有趣,您的怀疑——通过使三点类不可变进行预优化破坏了您的性能——听起来是正确的。您基本上是用交换整个对象来替换更改对象的内部(可变),并假设
gc
和运行时会更喜欢这样。正如您所说的,实例化和gc
调用现在正使工作陷入困境。所以你只有几个可能性:
gc
触发的次数,您可能可以提高性能。我对此表示怀疑,但至少你可以李>
编辑:更好地阅读您的第一段,我意识到您这样做是出于程序中的设计原因。如果是这样,不幸的是,实时编程是OO设计遇到运行时引擎严酷现实的地方 您正在为每个演员每秒创建160个三点。在每秒30帧时,这大约是每个演员每帧5帧。这使得每个演员每帧调用15次,仅用于读取三个点的坐标。 我相信,这不可能无限扩展
Actor::moveTo(x:Number,y:Number,z:Number):void
和Actor::moveBy(x:Number,y:Number,z:Number):void
有什么不对
另外,对于一个游戏,我认为这是一个更好的演员模型(只是一个草图):
下面的界面抽象了对参与者的所有影响(摩擦力、重力、推力等)
一个以恒定速度移动的演员只需要一个步骤。就这样。
你只需要在IActorAffector上创建每个可以作用于目标(吸引力来源等)的效果
不变性并不是那么错误,但在您的情况下,它似乎太昂贵了。另外,如果您管理好了这三个点,那么可能需要使用对象池来保持实例化和GC的低级别
如果事情对性能至关重要,您可能需要检查一下。它输出更快的字节码,允许低级别内存访问,并允许作为只读实例变量(编译时特性),这允许实现不变性,而无需对每个字段进行调用访问。使用Haxe还有很多其他原因,但我会让你自己去发现。听起来像是一个可怕的GC。我想知道,你是否检查过,以确保你没有意外地在某处留下引用?正如我在“我注意到我正在泄漏一些…”一句中提到的,我确实在泄漏对象。然而,泄漏对象的数量比创建和GC'd的对象数量少两个数量级。因此,我很乐于接受这样一个观点,即我的瓶颈是创造/破坏,而不是内存开销。达斯曼,这基本上是不相关的,但如果你不知道这些存在,你应该知道。我
package {
public class Actor {
private var _x:Number;
private var _y:Number;
private var _z:Number;
public var xs:Number;
public var ys:Number;
public var zs:Number;
public function Actor() {}
public function get x():Number { return _x; }
public function get y():Number { return _y; }
public function get z():Number { return _z; }
public function step():void {
this.x += this.xs;
this.y += this.ys;
this.z += this.zs;
}
}
}
package {
interface IActorAffector {
function applyTo(actor:Actor):void;
}
}