【发布时间】:2017-03-18 22:26:35
【问题描述】:
我目前正在尝试优化我用 Javascript 编写的游戏引擎。我遇到了很多问题,但这里有两个让我有点不知所措。
我有一个代表我游戏中玩家单位的类。玩家有 4 个单位,全部在游戏开始时创建。
我正在使用一些非常简单的东西,有点像:
function PartyCharacter()
{
this.Armor ;
this.FireResistance ;
this.CriticalStrike ;
// a hundred more like that
}
我认为未初始化的属性值不是非常安全/好的设计,并且可能会损害关于变量类型的 javascript 优化,因此我为它们分配了一个基本值:
function PartyCharacter()
{
this.Armor = 0 ;
this.FireResistance = 0 ;
this.CriticalStrike = 0 ;
// a hundred more like that
}
它让我在 Firefox 上的性能略有提升,但它让我在 chrome 上的整体性能下降了 300%。我很难弄清楚是什么原因造成的。我唯一注意到的是性能下降发生在一定数量的变量初始化(大约 15 次左右)之后。如果我只初始化 14,性能保持“正常”。再多加一个“=0”,性能一降再降。
我检查了 chrome profiler,问题似乎是它现在无法优化代码中的其他函数(函数优化太多)。这个新的 V8 优化问题涉及的 2 函数不直接与 Player 的单元交互,但它们确实调用了其他函数。 我已经在 V8 上尝试过 --trace ,但是因为我在 widnows 上,只是将标准输出重定向到控制台窗口并且窗口不允许复制/粘贴,而且垃圾邮件太多,无法阅读并在那里获取信息。
我对这种行为有点不知所措。
同样,我坚持将这些变量声明为原型,因为玩家单位的所有实例都使用它们。它让我在 FF 和 Chrome 上的性能下降了 20%。我不知道为什么会这样。
如果有帮助的话:我会大量访问这些变量并改变它们的值。
function PartyCharacter()
{
}
PartyCharacter.prototype.Armor = 0 ;
PartyCharacter.prototype.FireResistance = 0 ;
PartyCharacter.prototype.CriticalStrike = 0 ;
目前让我感到困惑的另一件事是浏览器之间的性能差异。 FF/Chrome 差不多,但 IE 总是慢 3 倍。
我尝试对游戏进行 60 秒的分析,看看 IE 上是否存在任何瓶颈,但单看分析结果,我会认为 IE 更快 O_o 我一定遗漏了一些东西。
我知道 FF(使用 firebug atm)和 IE 的分析器的工作方式有点不同,但我无法解释分析会话的结果。
在两个会话中,函数调用次数的比率是相同的。所以游戏逻辑对IE没有影响,只有函数内部花费的时间才能解释速度差异。
我看到,在 IE 上,我有 2 个函数的“自我”时间(不包括内部调用的函数)比它们在 FF 上的对应时间长得多:IE 上为 33%+17%,FF 上为 7%+2% .
问题是这些函数在 IE 上的平均时间比在 FF 上要短。
这意味着在两个浏览器上调用相同次数的函数在 IE 上执行得更快,但同时占用整个游戏过程的更多时间?出了点问题,某处....但我无法确定是什么。
这是我的 FF 分析数据的粘贴箱:http://pastebin.com/sjxWaz6p#
IE 也一样:http://pastebin.com/9NW1E0bg#
在 excel 中复制/粘贴原始数据,然后您就可以开始了!
【问题讨论】:
-
添加“太多”属性会损害 chrome 中的优化。 V8 有两种对象表示模式,超过一定数量会导致它去优化。但总的来说 - 在 v8 中赋值 is 比不这样做要快。
-
就像本杰明说的。更准确地说,如果一个对象有很多属性,Chrome 会自动使用哈希表而不是结构。如果您想继续使用结构,则必须将对象的属性拆分为多个对象(例如
this.resistances.fire而不是this.fireResistance)。 -
感谢第一部分的答案!最后,即使它们没有立即初始化,我的对象都具有所有列出的属性。这是否意味着如果我在构造函数之外初始化属性(我目前正在做的事情),v8 将优化为哈希?如果我在构造函数中初始化它们,他为什么不这样做?在这两种情况下,在我的代码中,我的对象具有完全相同数量的变量,但在一种情况下它是优化的,而在另一种情况下则不是。我有点困惑:)
-
@Touffy 适用于构造函数的规则与普通属性添加略有不同。 V8 实际上在构造函数中计算
this.propname形式的赋值数量,并相应地调整对象的“太多属性”限制(在一定范围内)。例如。使用最新的 V8function foo() { this.f0 = 0; /* ... */ this.f500 = 0; }构造快速(即非哈希表)对象当用作构造函数时new foo()。但是如果你使用像obj = {}; foo.call(obj);这样的东西,那么它会变得很慢。
标签: javascript internet-explorer optimization v8