v8 delete操作存在的这个问题
测试地址在这里,http://jsperf.com/test-v8-delete,也可以用下面的代码在node中测试
var begin = new Date();
function Foo() {}
Foo.prototype.x = 1;
Foo.prototype.y = 2;
//delete Foo.prototype.y;
var foo = new Foo();
var result = 0;
for (var i = 0; i < 100000000; i++) {
result = result + foo.x;
}
var end = new Date();
console.log(end - begin);
19 回复
我增加了property delete的对比测试,比起prototype的性能,property的delete差异不会太大。 prototype delete 差20倍,太夸张了。。。
我的测试结果:
$ node test-v8-delete.js
prototypeDeleteBenchmark:
delete: false, loop: 1000000, usetime: 8 ms
delete: true, loop: 1000000, usetime: 147 ms
propertyDeleteBenchmark:
delete: false, loop: 1000000, usetime: 4 ms
delete: true, loop: 1000000, usetime: 11 ms
我的测试脚本: test-v8-delete.js
function prototypeDeleteBenchmark(number, isDelete) {
function Foo() {}
Foo.prototype.x = 1;
Foo.prototype.y = 2;
if (isDelete) {
delete Foo.prototype.y;
}
var foo = new Foo();
var begin = new Date();
var result = 0;
for (var i = 0; i < number; i++) {
result = result + foo.x;
}
var end = new Date();
console.log('delete: %s, loop: %s, usetime: %d ms', isDelete, number, end - begin);
}
function propertyDeleteBenchmark(number, isDelete) {
var foo = {
x: 1,
y: 2
};
if (isDelete) {
delete foo.y;
}
var begin = new Date();
var result = 0;
for (var i = 0; i < number; i++) {
result = result + foo.x;
}
var end = new Date();
console.log('delete: %s, loop: %s, usetime: %d ms', isDelete, number, end - begin);
}
var number = parseInt(process.argv[2], 10) || 1000000;
console.log('prototypeDeleteBenchmark:');
prototypeDeleteBenchmark(number, false);
prototypeDeleteBenchmark(number, true);
console.log('propertyDeleteBenchmark:');
propertyDeleteBenchmark(number, false);
propertyDeleteBenchmark(number, true);
简单来说,V8认为多数数据的“结构是稳定”的,所以他就有一种优化方法,对一个类型生成一个对应的类,比如.prototype.x,他会生成带x属性的一个类,并通过静态的class这种类型,来引导x这个属性在对象所占内存中的偏移,同样再加上.prototype.y,就会生成有x和y两个属性的类
而问题就在这里,一但遇上delete,类型结构会被破坏,V8没办法通过预告固定的偏移(offset)值直接地获取某个属性的值,而必须一点一点地线性地查找,甚至需要在prototype链上查找属性,可以比较傻地理解为O(1)和O(n)的差距。
理论内容大家可以看看https://developers.google.com/v8/design#prop_access。
最后感谢灰大@otakustay 的解答。