首页 > 语言 > JavaScript > 正文

动态内存分配导致影响Javascript性能的问题

2024-05-06 15:27:16
字体:
来源:转载
供稿:网友

内存分配对性能的影响是很大的,分配内存本身需要时间,垃圾回收器回收内存也需要时间,所以应该尽量避免在堆里分配内存。不过直到最近优化HoLa cantk时,我才深刻的体会到内存分配对性能的影响,其中有一个关于arguments的问题挺有意思,写在这里和大家分享一下。

我要做的事情是用webgl实现canvas的2d API(这个话题本身也是挺有意思的,有空我们再讨论),drawImage是一个重要的函数,游戏会频繁的调用它,所以它的性能至关重要。drawImage的参数个数是可变的,它有三种形式:

drawImage(image, x, y) drawImage(image, x, y, width, height) drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

第一个版本大概是这样实现的:

function Context() {}Context.prototype.drawImage3 = function(image, x, y) {  this.drawImage9(image, 0, 0, image.width, image.height, x, y, image.width, image.height);}Context.prototype.drawImage5 = function(image, dx, dy, dw, dh) {  this.drawImage9(image, 0, 0, image.width, image.height, dx, dy, dw, dh);}Context.prototype.drawImage9 = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {  //DO IT}Context.prototype.drawImage = function(image, a, b, c, d, e, f, g, h) {  var n = arguments.length;  if(n === 3) {    this.drawImage3(image, a, b);  }else if(n === 5) {    this.drawImage5(image, a, b, c, d);  }else if(n === 9) {    this.drawImage9(image, a, b, c, d, e, f, g, h);  }}

为了方便说明问题,我把测试程序独立出来:

var image = {width:100, height:200};var ctx = new Context();function test() {  var a = Math.random() * 100;  var b = Math.random() * 100;  var c = Math.random() * 100;  var d = Math.random() * 100;  var e = Math.random() * 100;  var f = Math.random() * 100;  var g = Math.random() * 100;  var h = Math.random() * 100;  for(var i = 0; i < 1000; i++) {    ctx.drawImage(image, a, b);    ctx.drawImage(image, a, b, c, d);    ctx.drawImage(image, a, b, c, d, e, f, g, h);  }}window.onload = function() {  function loop() {    test();    requestAnimationFrame(loop);  }  requestAnimationFrame(loop);}

用chrome的Profile查看CPU的使用情况时,我发现垃圾回收的时间比例很大,一般在4%以上。当时并没有怀疑到drawImage这个函数,理由很简单:

这个函数很简单,它只是一个简单的分发函数,而drawImage9的实现相对来说要复杂得多。

这里看不出有动态内存分配,也没有违背arguments的使用规则,只是使用了它的length属性。

加trace_opt和trace_deopt参数运行时,drawImage被优化了,而且没有被反优化出来。

Chrome的内存Profile只能看到没有被释放的对象,用它查看内存泄露比较容易。这里的问题并不是泄露,而是分配了然后又释放了,V8采用的分代垃圾回收器,这种短时存在的对象是由年轻代回收器管理器负责的,而年轻代回收器使用的半空间(semi-space)算法,这种大量短时间生存的对象,很快会耗尽其中一半空间,这时回收器需要把存活的对象拷贝到另外一半空间中,这就会耗费大量时间,而垃圾回收时会暂停JS代码执行,如果能避免动态内存分配,减少垃圾回收器的工作时间,就能提高程序的性能。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选