javascript V8 优化和 "leaking arguments"

javascript V8 optimisation and "leaking arguments"

我在 various places 中读到,建议小心处理 arguments 对象,这没关系...

    var i = arguments.length, args = new Array(i);
    while (i--) args[i] = arguments[i];

但是,这样可以吗?...

function makeArray (l) {
    var i = l.length, array = new Array(i);
    while (i--) array[i] = l[i];
    return array;
};
//...
//EDIT: put the function on an object to better represent the actual case
var o = {};
o.f = function (callback) {
    var args = makeArray (arguments);
    callback.apply(args[0] = this, args);
};

"leaking arguments" 是什么意思,它对优化有何影响?

我专注于 V8,但我认为它也适用于其他编译器?

证明它有效...

function makeArray (l) {
    var i = l.length, array = new Array(i);
    while (i--) array[i] = l[i];
    return array;
};
//...
//EDIT: put the function on an object to better represent the actual case
var o = {};
o.f = function (callback) {
    var args = makeArray (arguments);
    callback.apply(args[0] = this, args);
};
o.m = "Hello, ";
function test(f, n) {
    alert(this.m + " " + n)
}
o.f(test, "it works...")

这是一个 2 重问题:

  1. 您将失去所有可能的优化和分支预测
    arguments 对象不可预测。
  2. 你泄漏了内存。真的很糟糕!

考虑以下代码(运行 风险自负!):

function a(){return arguments;}

x=a(document.getElementsByTagName('*'));

window._interval=setInterval(function(){

    for(var i=0;i<1e6;i++)
    {
        x=a(x);
    }
},5000);
*{font-family:sans-serif;}
<p>Warning! This may overheat your cpu and crash your browser really badly!</p>

<p>I'm not responsible for any software and hardware damages!</p>

<p><b>Run at your own risk!!!</b></p>

<p>If you ran this code, press F5 to stop or close the browser.</p>

<p>If you want, you can try to <button onclick="window.clearInterval(window._interval);window.x='';">stop it</button>. (the RAM may remain unchanged)</p>

现在观察你的 RAM 上升,当你 运行 时(它以每 5 秒大约 300-500MB 的速度上升)。
简单地传递参数的天真实现可能会导致这些问题。

更不用说您的代码(通常)会慢一点。


注意这个:

function a(){return arguments;}
function b(arg){return arg;}

x=a(document.getElementsByTagName('*'));

window._interval=setInterval(function(){

    for(var i=0;i<1e6;i++)
    {
        x=b(x);
    }
},5000);
*{font-family:sans-serif;}
<p>This may be safe, but be careful!</p>

<p>I'm not responsible for any software and hardware damages!</p>

<p><b>Run at your own risk!!!</b></p>

<p>If you ran this code, press F5 to stop or close the browser.</p>

<p>If you want, you can try to <button onclick="window.clearInterval(window._interval);window.x='';">stop it</button>.</p>

不会和之前的代码有同样的效果。
这是因为 b() returns 相同的变量,而不是对新 arguments 对象的新引用。
这是一个非常的重要区别。

arguments 的问题与本地 evalwith 的问题相同:它们会导致混叠。 Aliasing defeats all sorts of optimizations 因此,即使您启用了对此类函数的优化,您最终也可能只是在浪费时间,这是 JIT 的一个问题,因为花在编译器上的时间不是花在 运行 编码上的时间(尽管优化管道中的一些步骤可以 运行 并行)。

由于 arguments 泄漏导致的混叠:

function bar(array) {    
    array[0] = 2;
}

function foo(a) {
    a = 1;
    bar(arguments);
    // logs 2 even though a is local variable assigned to 1
    console.log(a);
}
foo(1);

请注意,严格模式消除了这一点:

function bar(array) {    
    array[0] = 2;
}

function foo(a) {
    "use strict";
    a = 1;
    bar(arguments);
    // logs 1 as it should
    console.log(a);
}
foo(1);

但是严格模式也没有优化,我不知道有什么合理的解释,除了基准测试不使用严格模式并且很少使用严格模式。这可能会改变,因为许多 es6 特性需要严格模式,在 es6 中不需要 otoh arguments 所以...