详解Node.js API系列C/C++ Addons(2) Google V8引擎

释放双眼,带上耳机,听听看~!

回顾,前文由node.js写的基于addon的hello world例子


1
2
3
4
5
6
7
8
9
10
11
12
1#include <node.h>
2#include <v8.h>
3using namespace v8; Handle<Value> Method(const Arguments& args) {
4  HandleScope scope;
5  return scope.Close(String::New("world"));
6}
7void init(Handle<Object> exports) {
8  exports->Set(String::NewSymbol("hello"),
9      FunctionTemplate::New(Method)->GetFunction());
10}
11NODE_MODULE(hello, init)
12

HandleScope scope这是什么玩意,哪里才能获取到它的介绍。请留意代码段中using namespace v8 ,实际上它调用了google v8的库,所以要了解node.js addon需要了解google v8引擎(以下简称v8)。

v8 是一个javascript解释引擎,跟传统javascript引擎不同,主要有四个特性

  • 快速的属性访问
  • 动态机器码生成
  • 高效的垃圾收集
  • 内联缓存机制

JIT编译(Just-in-time Compile)

以java为例子,java编译器会先将原始代码转换成语法树,语法树编译成虚拟中间语言(字节码),java vm按顺序解释字节码,解析成机器语言。

v8编译流程,编译器将原始代码转换成语法树后,直接解释成机器语言。

传统编译流程


1
2
1代码段 -> 语法树 -> 中间码 -> 机器语言
2

v8编译流程


1
2
1代码段 -> 语法树 -> 机器语言
2

高效内存管理

采用精确分代垃圾收集技术(Precise Generational GC)

年轻代,是一个较小的连续地址空间,经常进行收集。

年长代,被分成几个空间,不经常收集,先在年轻代里创立对象,没有被收集的对象被移到年长代

  • 可执行的代码空间
  • 存放隐藏类空间
  • 大的对象空间 (>8k)
  • 数据对象空间 (存放不含指针的对象)
  • 普通对象空间

垃圾收集技术

  • 清除收集

  • 只在年轻代使用复制收集算法

    • 间隙时间 2ms
  • 全堆非压缩收集

  • 对两代使用标记-清除收集算法

    • 空闲内存加入空闲列表
    • 可能产生碎片
    • 间隙时间 50ms
  • 全堆压缩收集

  • 对两袋使用标记-压缩收集算法

    • 间隙时间 100ms

隐藏类

传统的javascirpt引擎使用哈希表hash table来存取属性和方法,每次存取属性或找方法的时候,就会使用字符串作为寻找对象的哈希键key,搜寻哈希表是一个连续动作,首先通过散列(hashing)值判断数据内的位置,然后判断数组内的键值是否相等,如果不相等,位移到其他数组,方法比较费时。

相反,对于C++和JAVA等,编译的时候,会事先知道存储数据的类型和偏移量。

因此,V8通过隐藏类来简化索引,V8在定义对象的过程中,自动创建隐藏类,通过类的数组索引来查找对象的值。详细过程可以参考

内联缓存机制

当进行隐藏类的行为操作的时候,会被缓存,下一次采用相同的隐藏类行为的时候,能直接命中。

基于Google V8的Hello world


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1#include <v8.h>
2using namespace v8;
3int main(int argc, char* argv[]) {
4  // Get the default Isolate created at startup.
5  Isolate* isolate = Isolate::GetCurrent();
6  // Create a stack-allocated handle scope.
7  HandleScope handle_scope(isolate);
8  // Create a new context.
9  Handle<Context> context = Context::New(isolate);
10  // Here's how you could create a Persistent handle to the context, if needed.
11  Persistent<Context> persistent_context(isolate, context);
12
13  // Enter the created context for compiling and
14  // running the hello world script.
15  Context::Scope context_scope(context);
16  // Create a string containing the JavaScript source code.
17  Handle<String> source = String::New("'Hello' + ', World!'");
18  // Compile the source code.
19  Handle<Script> script = Script::Compile(source);
20
21  // Run the script to get the result.
22  Handle<Value> result = script->Run();
23
24  // The persistent handle needs to be eventually disposed.
25  persistent_context.Dispose();
26  // Convert the result to an ASCII string and print it.
27  String::AsciiValue ascii(result);
28  printf("%s\n", *ascii);
29 return 0;
30}
31

Isolate

Isolate表示一个独立的v8引擎实例,每个实例维护不同的状态。一个Isolate中的对象不能在其他Isolate中使用。当v8被初始化的时候,一个默认isolate被默认创建。开发者可以通过创建额外的Isolate在多线程环境下并行使用。一个Isolate任意时间只允许一个线程在其中运行,可以使用Locker和Unlocker来进行多个线程对一个Isolate的同步。

Context

V8允许不同的JavaScript代码运行在完全不同的环境下,其运行环境称为Context。不同的Context下拥有自己的全局对象(PersistentHandle),运行代码时必须指定所在的Context。最典型的例子就是Chrome的标签,每个标签都拥有自己的Context。
Context拥有自己的全局代理对象(global proxy object),每个Context下的全局对象都是这个全局代理对象的属性。通过Context::Global ()可以得到这个全局代理对象。新建Context时你可以手动指定它的全局代理对象,这样每个Context都会自动拥有一些全局对象,比如DOM。
Context也是一种scope,通过Context::Enter ()和Context::Exit ()来进入、退出,或者使用类似于HandleScope的Context::Scope来隐式进入。

Handle

V8里使用Handle类型来托管 JavaScript对象,与C++的std::shared_pointer类似,Handle类型间的赋值均是直接传递对象引用,但不同的是,V8使用自己的GC来管理对象生命周期,而不是智能指针常用的引用计数。如果一个v8对象没有任何Handle与之相关联(不再被访问),那么这个对象很快就会被垃圾回收器回收掉。
Handle有两种类型,Local Handle和Persistent Handle,类型分别是Local : Handle和Persistent : Handle,前者和Handle没有区别,生存周期都在scope内。而后者的生命周期脱离scope,你需要手动调用Persistent::Dispose结束其生命周期。也就是说Local Handle相当于在C++在栈上分配对象,而Persistent Handle相当于C++在堆上分配对象。

HandleScope

一个函数中,可以有很多Handle,而HandleScope则相当于用来装Handle(Local)的容器,当HandleScope生命周期结束的时候,Handle也将会被释放,会引起Heap中对象引用的更新。HandleScope是分配在栈上,不能通过New的方式进行创建。对于同一个作用域内可以有多个HandleScope,新的HandleScope将会覆盖上一个HandleScope,并对Local Handle进行管理。

参考资料

https://developers.google.com/v8/intro

http://blog.pluskid.org/?p=186

http://blog.chinaunix.net/uid-20357359-id-2690542.html

原文:http://blog.whattoc.com/2013/09/07/nodejs_api_addon_2/

给TA打赏
共{{data.count}}人
人已打赏
安全技术

对称加密和分组加密中的四种模式(ECB、CBC、CFB、OFB)

2021-8-18 16:36:11

安全技术

C++ 高性能服务器网络框架设计细节

2022-1-11 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索