Javascript 对象实例化大小和方法的巨大性能差异
Large performance variance with Javascript object instantiation size & methods
我注意到各种对象实例化方法之间存在显着的性能差异。此外,有时对象的大小(即属性的数量)似乎很重要。
任何人都可以阐明以下 jsperf 的结果吗?
http://jsperf.com/objects-w-more-less-8-properties/5
var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8}
这似乎是创建新对象的最快方法
var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9}
这要慢得多...唯一的区别是第 9 个值
var thisobj = new objsm(1,2,3,4,5,6,7,8);
和
var thisobj = new objlg(1,2,3,4,5,6,7,8,9);
彼此之间没有太大差异(与您期望的差不多),但它们与上面 'dynamically' 定义的对象仍然有很大差异。他们的对象在这里定义:
var objsm = function (a,b,c,d,e,f,g,h) {
this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h;}
var objlg = function (a,b,c,d,e,f,g,h,i) {
this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h; this.i = i; }
为什么“var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8}
”如此优越?
像这样的性能差异通常不是由于语言 javascript,而是由于该语言的实现。
其他因素,例如堆占用(以及由此产生的 GC 成本)也会影响性能。
由于存在多种实现 - 它们在不断发展 - 并且浏览器没有吐出生成的程序集的习惯,因此没有通用的答案。
例如,在 FF 45 上,我在所有四种情况下获得的性能几乎相同:
大概 JIT 编译器足够聪明,可以在这里执行死代码消除,所以我们实际上是在对一个空循环进行基准测试。换句话说,这个结果显示了编译器的优化程度,而不是对象分配的成本。
Making the objects escape 进入全局范围会产生以下结果,这与人们所期望的差不多:
请注意,足够先进的编译器™ 可能会从循环中消除除最后一次分配之外的所有分配,方法是观察它们都写入同一个变量而不在迭代之间读取。
所以未来的浏览器版本可能会再次"break"这个基准。
微基准测试是一项棘手的工作。
我的猜测是基于散列图的形式本地执行,而基于构造函数的形式执行需要解释的函数[=21] =].我想这种解释工作会导致性能差异。
那 8 个属性的门槛呢? HashMap 需要预先确定大小 超过它应包含的最大值数 (否则,访问时间会增加)。如果某些浏览器供应商选择了较低的值(例如 8-10),则每次尝试存储超过 8 个项目都会降低性能。
但是,您提到的 jsperf 中的 main 相关性并未超过测试,而是超过了浏览器:每个浏览器在所有测试中都显示出非常相似的结果, 这很有道理。
我注意到各种对象实例化方法之间存在显着的性能差异。此外,有时对象的大小(即属性的数量)似乎很重要。
任何人都可以阐明以下 jsperf 的结果吗? http://jsperf.com/objects-w-more-less-8-properties/5
var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8}
这似乎是创建新对象的最快方法
var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9}
这要慢得多...唯一的区别是第 9 个值
var thisobj = new objsm(1,2,3,4,5,6,7,8);
和
var thisobj = new objlg(1,2,3,4,5,6,7,8,9);
彼此之间没有太大差异(与您期望的差不多),但它们与上面 'dynamically' 定义的对象仍然有很大差异。他们的对象在这里定义:
var objsm = function (a,b,c,d,e,f,g,h) {
this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h;}
var objlg = function (a,b,c,d,e,f,g,h,i) {
this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h; this.i = i; }
为什么“var thisobj = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8}
”如此优越?
像这样的性能差异通常不是由于语言 javascript,而是由于该语言的实现。
其他因素,例如堆占用(以及由此产生的 GC 成本)也会影响性能。
由于存在多种实现 - 它们在不断发展 - 并且浏览器没有吐出生成的程序集的习惯,因此没有通用的答案。
例如,在 FF 45 上,我在所有四种情况下获得的性能几乎相同:
大概 JIT 编译器足够聪明,可以在这里执行死代码消除,所以我们实际上是在对一个空循环进行基准测试。换句话说,这个结果显示了编译器的优化程度,而不是对象分配的成本。
Making the objects escape 进入全局范围会产生以下结果,这与人们所期望的差不多:
请注意,足够先进的编译器™ 可能会从循环中消除除最后一次分配之外的所有分配,方法是观察它们都写入同一个变量而不在迭代之间读取。
所以未来的浏览器版本可能会再次"break"这个基准。
微基准测试是一项棘手的工作。
我的猜测是基于散列图的形式本地执行,而基于构造函数的形式执行需要解释的函数[=21] =].我想这种解释工作会导致性能差异。
那 8 个属性的门槛呢? HashMap 需要预先确定大小 超过它应包含的最大值数 (否则,访问时间会增加)。如果某些浏览器供应商选择了较低的值(例如 8-10),则每次尝试存储超过 8 个项目都会降低性能。
但是,您提到的 jsperf 中的 main 相关性并未超过测试,而是超过了浏览器:每个浏览器在所有测试中都显示出非常相似的结果, 这很有道理。