v8的一些文档翻译
@from
https://gist.github.com/kevincennis/0cd2138c78a07412ef21
Installing V8 on a Mac
先决条件
安装Xcode(可在Mac App Store)
安装Xcode的命令行工具(偏好>下载)
安装depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
sudo nano ~/.bash_profile
Add export PATH=/path/to/depot_tools:”$PATH” (重要)
source ~/.bash_profile
进入你想安装V8的目录,运行gclient
Build V8
fetch v8 cd v8 gclient sync tools/dev/v8gen.py x64.optdebug ninja -C out.gn/x64.optdebug
(prepare for lots of fan noise)
I’d also recommend adding some aliases to your .bash_profile:
sudo nano ~/.bash_profile
Add
alias d8=/path/to/v8/repo/out.gn/x64.optdebug/d8
Add
alias tick-processor=/path/to/v8/repo/tools/mac-tick-processor
source ~/.bash_profile
d8 shell examples
打印优化的数据
创建下面的test.js代码:
function test( obj ) { return obj.prop + obj.prop; } var a = { prop: 'a' }, i = 0; while ( i++ < 10000 ) { test( a ); }
Run
d8 --trace-opt-verbose test.js
你应该看到测试函数是由V8优化的,以及为什么会被优化的解释。 “IC”代表内联缓存,是V8执行优化的方式之一。 一般来说,“typeinfo”的IC越多越好。
现在修改test.js以包含以下代码:
function test( obj ) { return obj.prop + obj.prop; } var a = { prop: 'a' }, b = { prop: [] }, i = 0; while ( i++ < 10000 ) { test( Math.random() > 0.5 ? a : b ); }
运行
d8 --trace-opt-verbose test.js
所以,你会看到,这一次,test函数从未被实际优化。 原因是因为它被传递给具有不同隐藏类的对象。 尝试将prop中的值更改为一个整数并再次运行。 您应该会看到该函数能够被优化。
打印去优化统计
修改test.js的内容:
function test( obj ) { return obj.prop + obj.prop; } var a = { prop: 'a' }, b = { prop: [] }, i = 0; while ( i++ < 10000 ) { test( i !== 8000 ? a : b ); }
Run
d8 --trace-opt --trace-deopt test.js
您应该看到test函数的优化代码被抛出。 这里V8一直看到测试被传递一个像{prop:
Profiling
Modify test.js:
function factorial( n ) { return n === 1 ? n : n * factorial( --n ); } var i = 0; while ( i++ < 1e7 ) { factorial( 10 ); }
Run
time d8 --prof test.js
(Generates v8.log)
Run
tick-processor
(Reads v8.log and cats the parsed output)
这将显示程序大部分时间在函数上的消耗。 大部分应该在LazyCompile下:* factorial test.js:1:19。 功能名称前的星号表示已经进行了优化。
记录登录到终端的执行时间。 现在尝试修改代码到这个愚蠢的例子:
function factorial( n ) { return equal( n, 1 ) ? n : multiply( n, factorial( --n ) ); } function multiply( x, y ) { return x * y; } function equal( a, b ) { return a === b; } var i = 0; while ( i++ < 1e7 ) { factorial( 10 ); }
Run
time d8 --prof test.js
Run
tick-processor
与最后一个函数大致相同的执行时间,但是按照我们的想法,这个例子似乎应该更快。 你还会注意到,这个multi和equal的函数在列表中不存在。 奇怪,对吧?
运行d8 –trace-inlining test.js
我们可以看到,优化编译器在这里是很聪明的,并且完全消除了调用这两个函数的开销,它们将它们归结为优化的阶乘代码。两个版本的优化代码最终基本相同(如果您知道如何读取程序集,可以通过运行d8 –print-opt-code test.js来检查)。
Tracing Garbage Collection
Modify test.js
function strToArray( str ) { var i = 0, len = str.length, arr = new Uint16Array( str.length ); for ( ; i < len; ++i ) { arr[ i ] = str.charCodeAt( i ); } return arr; } var i = 0, str = 'V8 is the collest'; while ( i++ < 1e5 ) { strToArray( str ); }
Run
d8 --trace-gc test.js
You’ll see a bunch of
Scavenge... [allocation failure].
基本上,V8的GC堆具有不同的“空间”。 大多数对象都分配在“新空间”中。 在这里分配代价超低,但它也很小(通常在1到8 MB之间)。 一旦这个空间被填满,GC就会进行“清理”。
清理是V8垃圾收集的快速部分。 通常从我所看到的介于1到5ms之间 - 所以它可能不一定会引起明显的GC暂停。
清除只能通过分配来启动。 如果“新空间”从未被填满,则GC不需要通过清理来回收空间。
Modify test.js:
function strToArray( str, bufferView ) { var i = 0, len = str.length; for ( ; i < len; ++i ) { bufferView[ i ] = str.charCodeAt( i ); } return bufferView; } var i = 0, str = 'V8 is the coolest', buffer = new ArrayBuffer( str.length * 2 ), bufferView = new Uint16Array( buffer ); while ( i++ < 1e5 ) { strToArray( str, bufferView ); }
在这里,我们使用预分配的ArrayBuffer和相关联的ArrayBufferView(在本例中为Uint16Array),以避免每次运行strToArray()时重新分配一个新对象。 结果是我们几乎没有分配任何东西。
运行d8 –trace-gc test.js
没有。 我们从来没有填补“新空间”,所以我们从来没有去过。
在test.js中再试一次:
function strToArray( str ) { var i = 0, len = str.length, arr = new Uint16Array( str.length ); for ( ; i < len; ++i ) { arr[ i ] = str.charCodeAt( i ); } return arr; } var i = 0, str = 'V8 is the coolest', arr = []; while ( i++ < 1e6 ) { strToArray( str ); if ( i % 100000 === 0 ) { // save a long-term reference to a random, huge object arr.push( new Uint16Array( 100000000 ) ); // release references about 5% of the time Math.random() > 0.95 && ( arr.length = 0 ); } }
运行d8 –trace-gc test.js
可以看到有许多清除,因为我们不再使用预分配的缓冲区。 但也应该有一堆mark-sweep。
标记扫描(mark-sweep)是“完整”的GC。 当“旧空间”堆达到一定的大小时,它会运行,而且比普通清理时间更长。 如果您查看日志,您可能会看到Scavenge 约1.5ms,Mark-sweep更接近25或30ms。
由于网络应用程序中的帧预算约为16ms,所以每次Mark-sweep运行时,都至少丢弃1帧。
杂项
d8 –help记录所有可用的d8标志
有一大堆文字,但你通常可以找到你想要的东西,像d8 –help | grep 就可以找到你要的东西。
d8 –allow-natives-syntax file.js
这实际上可以让您从JS文件中调用V8内部方法,如下所示:
function factorial( n ) { return n === 1 ? n : factorial( --n ); } var i = 0; while ( i++ < 1e8 ) { factorial( 10 ); // run a full Mark-sweep pass every 10MM iterations i % 1e7 === 0 && %CollectGarbage( null ); }
…并运行d8 –allow-natives-syntax –trace-gc test.js
本机功能前缀为%符号。 这里列出了一些(有些不完整)的本机功能列表。
记录
d8没有控制台对象(或窗口对象)。 但是您可以使用print()。
比较隐藏类
这可能是我最喜欢的。 我其实刚找到它。
所以在V8中,这个概念就是“隐藏的类”(好几个段落的解释)。 你应该阅读这篇文章 - 但是基本上隐藏的类是V8(SpiderMonkey和JavaScript Core也使用类似技术)来确定两个对象是否具有相同的“形状”。
所有考虑的事情,你总是希望将相同隐藏类的对象作为参数传递给函数。
无论如何,您可以实际比较两个对象的隐藏类:
function Class( val ) { this.prop = val; } var a = new Class('foo'); var b = new Class('bar'); print( %HaveSameMap( a, b ) ); b.prop2 = 'baz'; print( %HaveSameMap( a, b ) );
运行d8 –allow-natives-syntax test.js
你应该看到true、false。 通过添加b.prop2 =’baz’,我们修改了它的结构并创建了一个新的隐藏类。
Node.js
很多这些标志(但不是全部)可与Node一起使用。 –trace-opt,–prof,–allow-natives-syntax都支持。
如果您想要测试依赖于另一个库的内容,那么可以使用,因为您可以使用Node的require()。
可以使用node –v8-options选项访问支持的V8标志列表。