从不运行的线路是否会影响 V8 的性能?
Does the line which never runs affect performance in V8?
我想知道这两个代码运行速度不同的原因。
fast.js
var N = 2e9;
(function () {
console.time();
var count = 0;
for (var i = 0; i < N; i++) count++;
if(false) console.log(count);
console.timeEnd()
})();
slow.js
var N = 2e9;
(function () {
console.time();
var count = 0;
for (var i = 0; i < N; i++) count++;
if(false) (() => console.log(count));
console.timeEnd()
})();
执行
% node fast.js
default: 1.297s
% node slow.js
default: 3.175s
代码之间的区别在于第 6 行。
if(false) console.log(count);
if(false) (() => console.log(count));
但这些部分从来没有 运行 因为它是死代码。
@tkihira分析得出,变量count
分配在堆中是因为它在slow.js运行时用于闭包,所以需要更多的时间来增加它for 循环。而 fast.js 中的 count
在寄存器中。
这造成了速度差异。
有谁知道 V8 中代码的哪一部分造成了这种行为?
当一个数字变量在一个永远不会 运行s 的闭包和一个变量中使用时,它是在堆中分配的,并且当它不在闭包中使用时它在寄存器中,这是真的吗?
@tkihira 的分析:
源代码:https://gist.github.com/tkihira/b9c7fe8c31e21f1022011e377f7e672d
jit 输出:https://gist.github.com/tkihira/67a07231cc6a4ce55462d8cdfa51a6e2
差异:https://gist.github.com/tkihira/5f5877cde581c66cae3bc02f88e505e4
(此处为 V8 开发人员。)
Does anyone know which part of the code in V8 makes this behavior?
它是“作用域解析”系统的一部分,大部分代码在src/ast/scopes.cc
中。 (它相当复杂,因为它要处理的事情太多了。)
Is it true that a number variable is allocated in heap when it's used in a closure that never runs and a variable and it's in a register when it's not used in a closure?
是的。
变量是否包含数字或其他任何内容都没有关系。
闭包 运行 的频率并不重要,包括它是否会 运行。在需要决定在何处分配变量时,尚无关于将执行或不执行的信息。 (此外,静态保证永远不会执行的闭包在实际代码中非常罕见,即使可能,也很可能不值得对其进行优化。)
闭包使用的变量是“上下文分配的”,这使得访问它们比“堆栈分配的”变量慢一点。 If/when 有问题的函数得到了优化,堆栈分配的变量可能会或可能不会最终保留在寄存器中,这取决于优化编译器做出的其他寄存器分配决定。
在大多数现实世界的情况下,您不会注意到差异(因此这通常不值得担心),但是像循环这样的微基准测试只做 count++
可以观察到。
我想知道这两个代码运行速度不同的原因。
fast.js
var N = 2e9;
(function () {
console.time();
var count = 0;
for (var i = 0; i < N; i++) count++;
if(false) console.log(count);
console.timeEnd()
})();
slow.js
var N = 2e9;
(function () {
console.time();
var count = 0;
for (var i = 0; i < N; i++) count++;
if(false) (() => console.log(count));
console.timeEnd()
})();
执行
% node fast.js
default: 1.297s
% node slow.js
default: 3.175s
代码之间的区别在于第 6 行。
if(false) console.log(count);
if(false) (() => console.log(count));
但这些部分从来没有 运行 因为它是死代码。
@tkihira分析得出,变量count
分配在堆中是因为它在slow.js运行时用于闭包,所以需要更多的时间来增加它for 循环。而 fast.js 中的 count
在寄存器中。
这造成了速度差异。
有谁知道 V8 中代码的哪一部分造成了这种行为? 当一个数字变量在一个永远不会 运行s 的闭包和一个变量中使用时,它是在堆中分配的,并且当它不在闭包中使用时它在寄存器中,这是真的吗?
@tkihira 的分析: 源代码:https://gist.github.com/tkihira/b9c7fe8c31e21f1022011e377f7e672d
jit 输出:https://gist.github.com/tkihira/67a07231cc6a4ce55462d8cdfa51a6e2
差异:https://gist.github.com/tkihira/5f5877cde581c66cae3bc02f88e505e4
(此处为 V8 开发人员。)
Does anyone know which part of the code in V8 makes this behavior?
它是“作用域解析”系统的一部分,大部分代码在src/ast/scopes.cc
中。 (它相当复杂,因为它要处理的事情太多了。)
Is it true that a number variable is allocated in heap when it's used in a closure that never runs and a variable and it's in a register when it's not used in a closure?
是的。
变量是否包含数字或其他任何内容都没有关系。
闭包 运行 的频率并不重要,包括它是否会 运行。在需要决定在何处分配变量时,尚无关于将执行或不执行的信息。 (此外,静态保证永远不会执行的闭包在实际代码中非常罕见,即使可能,也很可能不值得对其进行优化。)
闭包使用的变量是“上下文分配的”,这使得访问它们比“堆栈分配的”变量慢一点。 If/when 有问题的函数得到了优化,堆栈分配的变量可能会或可能不会最终保留在寄存器中,这取决于优化编译器做出的其他寄存器分配决定。
在大多数现实世界的情况下,您不会注意到差异(因此这通常不值得担心),但是像循环这样的微基准测试只做 count++
可以观察到。