学习 v8 编程的好处就是能够知道 node 是如何通过写JavaScript进行调用系统 API 的,如果你有c/c++又或者是比较底层的语言的基础,研究明白 v8 是如何调用系统底层的,而系统是如何提供函数给v8调用的,那么我们对 node 的理解层度就会更上一层楼。
本节主要折腾的几个事情
- 如何通过JS调用c/c++层
- 如何通过c/c++层调用JS层
- 如何通过JS调用c++的类
当我们实现以上的JS-C/C++层的调用时,我们距离自己造一个node.js已经不远了
V8概念梳理
v8 执行代码的过程主要是:
- JavaScript源码输入
- 转换成AST(抽象语法树)
- JIT(just in time)
- NativeCode
这对于我们编程有了最初的印象,接下来,我们介绍一下各个内部的概念
v8::Isolate
Isolate 的概念给大家来看一定非常陌生,其英文原意是:隔离。在操作系统中,我们有一个概念和之类似:进程。进程是完全相互隔离的,一个进程里有多个线程,同时各个进程之间并不相互共享资源。Isolate 也是一样,Isolate1和Isolate2两个拥有各自堆栈的虚拟机实例,且相互完全隔离。
- An isolate is a VM instance with its own heap. It represents an isolated instance of the V8 engine. V8 isolates have completely separate states. Objects from one isolate must not be used in other isolates.
v8::handle(v8::Local和v8:Persistent)
在新的版本中,v8::handle拆成了更为形象的两个类:v8::Local和v8:Persistent。用一个更形象的比喻,那么v8::Local更像是JavaScript中的let。在 V8 中,内存的分配都交付给了 V8,那么我们就最好不要使用自己的 new 方法来创建对象,而是使用 v8::Local 里的各种方法来创建一个对象。由v8::Local创建的对象,能够被 v8 自动进行管理,也就是传说中的GC(垃圾清理机制)。
Persistent代表的是持久的意思,更类似全局变量,申请和释放一定要记得使用:Persistent::New, Persistent::Dispose这两个方法,否则会内存侧漏。
Scope
Scope是一个比较小范围的GC单元,分别有v8::HandleScope
和v8::Context::Scope
。
v8::HandleScope
一般情况下,HandleScope会在一个函数的开头进行声明,然后用于管理这整个函数所创建的Handle,而v8::Context::Scope
也类似,只不过他是直接管理context
对象的。
void F(){
//一开头放一个
v8::HandleScope handle_scope(isolate);
v8::Local<v8::String> source1 =.......
v8::Local<v8::String> source2 =......
//开头放一个
v8::Local<v8::Context> context = Context::New(isolate);
v8::Context::Scope context_scope(context);
}
这样一来,整个函数的handle和context就会被这两个scope分别管理起来,函数跑完了,那么就会自动释放掉了。
Context
Context的概念我更喜欢把比喻成闭包,虽然不是,但是很像。在V8里面,Context主要是用于创建一个JavaScript的运行上下文环境。更形象生动的说法是Html的iFrame,一个网页中可以有多个iFrame,每个iFrame又有不同的运行环境。