高性能javascript中的对象池?
我正在编写一些javascript代码,这些代码需要快速运行,并且使用了大量短期对象。我最好使用对象池,还是根据需要创建对象 我写了一篇文章,指出使用对象池没有任何好处,但是我不确定jsperf基准测试是否运行足够长的时间,以便浏览器的垃圾收集器启动高性能javascript中的对象池?,javascript,performance,Javascript,Performance,我正在编写一些javascript代码,这些代码需要快速运行,并且使用了大量短期对象。我最好使用对象池,还是根据需要创建对象 我写了一篇文章,指出使用对象池没有任何好处,但是我不确定jsperf基准测试是否运行足够长的时间,以便浏览器的垃圾收集器启动 代码是游戏的一部分,所以我不关心传统浏览器的支持。我的图形引擎无论如何都无法在旧浏览器上工作。对象池用于避免通过重新使用现有对象来创建新对象的实例化成本。只有当实例化对象的成本大于使用池所产生的开销时,这才有用 您已经证明,非常简单的对象不会从池中
代码是游戏的一部分,所以我不关心传统浏览器的支持。我的图形引擎无论如何都无法在旧浏览器上工作。对象池用于避免通过重新使用现有对象来创建新对象的实例化成本。只有当实例化对象的成本大于使用池所产生的开销时,这才有用
您已经证明,非常简单的对象不会从池中获益。随着对象变得更加复杂,这可能会发生变化。我的建议是遵循KISS原则,忽略对象池,直到对象创建速度被证明太慢。对象池可能会有所帮助,特别是当您正在处理大量对象时。我最近就这个问题写了一篇文章,可能值得一读 一般来说(以我个人的经验),池对象不会提高速度。创建对象通常非常便宜。相反,对象池的目的是减少垃圾收集引起的周期性延迟 作为一个具体的例子(不一定是JavaScript,但作为一个通用的例子),请考虑使用高级3D图形的游戏。如果一个游戏的平均帧速率为60fps,那么这比另一个平均帧速率为40fps的游戏要快。但是,如果第二场比赛的fps始终为40,图形看起来很平滑,而如果第一场比赛的fps通常高于60 fps,但偶尔会下降到10 fps,图形看起来很起伏 如果您创建一个基准测试,运行两个游戏10分钟,并每隔一段时间采样一次帧速率,它将告诉您第一个游戏的性能更好。但它不会在波涛汹涌中恢复。这就是对象池要解决的问题 当然,这不是一个涵盖所有案例的笼统声明。当您经常分配大型阵列时,池不仅可以改善断断续续性,还可以改善原始性能:通过简单地设置
arr.length=0
并重用arr
,您可以通过避免将来的重新调整大小来提高性能。类似地,如果您经常创建非常大的对象,这些对象都共享一个公共模式(即,它们有一组定义良好的属性,因此在将对象返回池时不必“清理”每个对象),那么在这种情况下,也可能会看到池的性能改进
正如我所说,一般来说,这不是对象池的主要目标。我认为这取决于对象的复杂性。我最近优化了一个JavaScript字处理器,它为文档中的每个元素使用JS对象和DOM对象。在实现对象池之前,我的测试文档的加载时间约为480ms。池技术将其减少到220ms
这当然是个轶事,但在我的例子中,它大大增加了应用程序的快速性,我现在经常在对象周转率高的应用程序中使用池。让我先说一句:我建议不要使用池,除非你正在开发可视化,游戏或其他计算昂贵的代码,实际上做了很多工作。你的web应用程序一般都是I/O绑定的,你的CPU和RAM大部分时间都是空闲的。在这种情况下,通过优化I/O而不是执行速度,您可以获得更多;i、 e.确保文件加载速度快,并且采用客户端而不是服务器端渲染+模板。然而,如果您正在玩弄游戏、科学计算或其他CPU绑定的Javascript代码,本文可能会让您感兴趣 短版: 在性能关键代码中:
String
),因为在对其执行状态更改操作期间,这些将创建新对象- 对于长寿命对象和短命对象,可能必须使用不同的池,以避免短命池的碎片化
- 您希望针对不同的场景比较不同的算法和不同的池粒度(池整个对象还是只池一些对象属性?)
- 池增加了代码的复杂性,从而使优化器的工作更加困难,可能会降低性能
首先,考虑系统堆与大型对象池基本相同。这意味着,每当您创建一个新对象(使用
new
、[]
、{}
、()
、字符串串联等)时,系统都会使用一种(非常复杂、快速且低水平的性能调整)算法来为您提供一些未使用的空间(即对象),确保将其字节清零并返回它。这非常类似于一个物体
var x = new X(...);
var x = X.create(...);
// this keeps all your allocation in the control of `Allocator`:
var x = Allocator.createX(...); // or:
var y = Allocator.create('Y', ...);
function add(a, b) { return new Vector(a.x + b.x, a.y + a.y); }
// ...
var z = add(x, y);
function add(out, a, b) { out.set(a.x + b.x, a.y + a.y); return out; }
// ...
var z = add(x, x, y); // you can do that here, if you don't need x anymore (Note: z = x)
var tmp = new X(...);
for (var x ...) {
tmp.set(x);
use(tmp); // use() will modify tmp instead of x now, and x remains unchanged.
}