【问题标题】:Javascript Optimization : issue on V8 and on IEJavascript 优化:V8 和 IE 上的问题
【发布时间】: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 形式的赋值数量,并相应地调整对象的“太多属性”限制(在一定范围内)。例如。使用最新的 V8 function foo() { this.f0 = 0; /* ... */ this.f500 = 0; } 构造快速(即非哈希表)对象当用作构造函数时 new foo()。但是如果你使用像obj = {}; foo.call(obj); 这样的东西,那么它会变得很慢。

标签: javascript internet-explorer optimization v8


【解决方案1】:

通常,在构造函数中初始化字段肯定是有意义的,并且应该会提高性能。您的第一个 sn-p (function PartyCharacter() { this.Armor ; ...) 不会创建任何字段。它读取 .Armor 字段,该字段不存在,因此读取返回 undefined;它确实以任何方式更改对象;并且 V8 也不会将此作为属性将在以后创建的暗示。

您在初始化这些字段时看到的速度变慢可能是由于其中存储了不同的类型。 V8 对类字段进行了一定数量的类型跟踪,但是当这些类型在执行后期发生变化时,这可能会导致性能成本。以后存储的所有值都是整数吗?他们会是双打吗?它们会是字符串/布尔值/对象吗?尝试将字段初始化为undefined(如果它们稍后会存储对象;或者NaN,如果它们只是数字),看看是否有帮助。

如果您稍后要覆盖它们,初始化原型上的属性将无济于事(因为这些写入不会转到原型,它们会在对象本身上创建字段)。另一方面,如果它们是“常量”(即从未改变),那么将它们存储在原型中是保留它们的最节省内存的方式。

(我对其他浏览器一无所知,所以我无法帮助解决有关 FF/IE 的问题。)

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2010-11-04
    • 2021-11-14
    • 2013-10-07
    • 1970-01-01
    相关资源
    最近更新 更多