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

徐君植
2023-12-01

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

#include <node.h>
#include <v8.h>
using namespace v8;
Handle<Value> Method(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));
}
void init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("hello"),
      FunctionTemplate::New(Method)->GetFunction());
}
NODE_MODULE(hello, init)

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编译流程,编译器将原始代码转换成语法树后,直接解释成机器语言。

传统编译流程

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

v8编译流程

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

高效内存管理

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

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

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

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

垃圾收集技术

  • 清除收集
    • 只在年轻代使用复制收集算法
    • 间隙时间 2ms
  • 全堆非压缩收集
    • 对两代使用标记-清除收集算法
    • 空闲内存加入空闲列表
    • 可能产生碎片
    • 间隙时间 50ms
  • 全堆压缩收集
    • 对两袋使用标记-压缩收集算法
    • 间隙时间 100ms

隐藏类

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

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

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

内联缓存机制

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

基于Google V8的Hello world

#include <v8.h>
using namespace v8;
int main(int argc, char* argv[]) {
  // Get the default Isolate created at startup.
  Isolate* isolate = Isolate::GetCurrent();
  // Create a stack-allocated handle scope.
  HandleScope handle_scope(isolate);
  // Create a new context.
  Handle<Context> context = Context::New(isolate);
  // Here's how you could create a Persistent handle to the context, if needed.
  Persistent<Context> persistent_context(isolate, context);

  // Enter the created context for compiling and
  // running the hello world script. 
  Context::Scope context_scope(context);
  // Create a string containing the JavaScript source code.
  Handle<String> source = String::New("'Hello' + ', World!'");
  // Compile the source code.
  Handle<Script> script = Script::Compile(source);

  // Run the script to get the result.
  Handle<Value> result = script->Run();

  // The persistent handle needs to be eventually disposed.
  persistent_context.Dispose();
  // Convert the result to an ASCII string and print it.
  String::AsciiValue ascii(result);
  printf("%s\n", *ascii);
  return 0;
}

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/

 类似资料: