v8 can not handle delete yet
发布于 3年前 作者 jin52yang 2384 次浏览

v8 delete操作存在的这个问题

enter image description here

测试地址在这里,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 回复

需要profile下看看具体情况

delete 操作看来是会有性能问题

这个是因为delete要返回一个Boolean值(true or false). 直接Foo.prototype.y = null;速度会更快.

嗯,意思是delete尽量不要用,delete形同虚设

delete 会引起GC嘛。

可以使用下面的接口来计算时间,不用Date:

console.time(‘deleteTime’); … … console.timeEnd(‘deleteTime’);//打印出执行时间.

我增加了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);

@jin52yang 不过对prototype进行delete的操作,目前我参与的项目中还没写过呢。。。

那就是说property delete 是没问题的吧。

反正 prototype delete从来没用过。

@guilin 是啊,property delete我用得蛮多的,于是就加上对比测试了。

@suqian @ @guilin property的delete性能差异相差不大,那个差异是因为在寻找对象的属性的时候,先去对象实例中看有没有这个属性,然后再去原型中寻找,delete掉实例中的属性就去再去原型中寻找,所以慢一点点。但是delete prototype 为啥会出现现在这么大的差异很费解。

@suqian 我没有实际场景需要用到这个;因为很喜欢Node,所以我最近在系统学习javascript中,这个我也是看到别人的测试用例,但是实在不明白为什么,我也没找到答案。

简单来说,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 的解答。

有空整理一下。学习之

@suqian delete可以完全删除实例属性,没试过删原型中的属性。

有理有据,令人信服

回到顶部