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 重问题:
- 您将失去所有可能的优化和分支预测
arguments
对象不可预测。
- 你泄漏了内存。真的很糟糕!
考虑以下代码(运行 风险自负!):
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
的问题与本地 eval
和 with
的问题相同:它们会导致混叠。 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
所以...
我在 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 重问题:
- 您将失去所有可能的优化和分支预测
arguments
对象不可预测。 - 你泄漏了内存。真的很糟糕!
考虑以下代码(运行 风险自负!):
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
的问题与本地 eval
和 with
的问题相同:它们会导致混叠。 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
所以...