我正在研究浏览器游戏的一个非常关键的性能部分,只是将一大堆代码拆分成更易于管理的块,但似乎我付出了相当大的(总共约 40%)的性能这些额外函数调用的损失。
起初我认为 V8 只是在编译时不进行内联,但后来我尝试了这个小测试:
const nn = 1000000000;
(()=>{
var t = Date.now();
var total = 0;
for (var i = 0; i < nn; i++) {
total += i;
}
console.log(total, Date.now() - t);
})();
(()=>{
var t = Date.now();
var total = 0;
function useless() {}
for (var i = 0; i < nn; i++) {
total += i;
useless();useless();useless();
}
console.log(total, Date.now() - t);
})();
(new class {
useless() {}
test() {
var t = Date.now();
var total = 0;
for (var i = 0; i < nn; i++) {
total += i;
this.useless();this.useless();this.useless();
}
console.log(total, Date.now() - t);
}
}).test();
并且在每种情况下,我都得到相同的结果,无论是否调用无用的函数。这告诉我,无用的函数调用几乎没有成本。
然而,在我的真实代码中,添加无用的函数调用会为每个添加的函数带来非常实际的惩罚,例如在
add_expected_length(v) {
this.set_block_raw(); // <- this is the useless one
while (v > 127) { this.buffer.push((v & 127) + 128); v = Math.trunc(v / 128); }
this.buffer.push(v);
}
即使 set_block_raw 方法是空的,在那里添加它会使整个算法慢 5%,连续添加两个和它的 7%,三个是 9% 等等,它似乎随着每个无用的调用几乎线性扩展补充说我的性能下降了 1-2%。
现在如果我把我的班级分开并开始检查单个调用,在这里和那里隔离代码片段,问题就会消失,无用的调用被忽略,但试图找出这种巨大的相互依赖算法中的问题所在只会花很长时间。
这对我来说似乎很奇怪,我真的很想深入研究 V8 生成的内容,看看是什么导致了这种情况。有没有办法窥视 js 并查看 chrome 和 V8 实际用它做什么?