Slide 1

Slide 1 text

Node.js 底层初探 Minqi Pan

Slide 2

Slide 2 text

I’m Minqi Pan github.com/pmq20 twitter @psvr

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

(evented)
 a model of I/O
 + (JavaScript)
 a language that was well suited to the style of programming = Node.js

Slide 6

Slide 6 text

浏览器的影⼦子 • v8 “上下⽂文”的设计:each window and iframe in a browser can have its own fresh JavaScript environment. [提问 node] • v8 限制堆的⼤大⼩小,浏览器不太可能⽤用⼤大量量内存 • node::Buffer (跳过 V8的内存分配,堆外内存)
 与 v8::Uint8Array / TypedArray 的故事 • CESU-8 encoding

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

C++ 11 (env.cc) auto close_and_finish = [](Environment* env, uv_handle_t* handle, void* arg) { … }

Slide 10

Slide 10 text

启动过程 node_main.cc * main() void LoadEnvironment(Environment* env) Local script_name = FIXED_ONE_BYTE_STRING(env->isolate(), "node.js"); * node.js * [hack]

Slide 11

Slide 11 text

API 源码定位

Slide 12

Slide 12 text

JavaScript API • v8 内置 API:v8/src/js/array.js … v8/src/js/weak- collection.js • Node.js ⽂文档记载的公开 API:assert.js … zlib.js • Node.js 的私有 API:internal/* 
 与公开 API 同名,internal/bootstrap_node.js 除外 • API ⼦子⽂文件:_debug_agent.js … _tls_wrap.js

Slide 13

Slide 13 text

C++ API • process.binding 系列列 • 注册发⽣生在每个 *.cc ⽂文件的最后
 (NODE_MODULE宏) • 引⽤用⽅方式 [demo]:
 process.binding('cares_wrap');

Slide 14

Slide 14 text

v8 内置 API • create the built-in objects and parse the built-in JavaScript code when creating v8::Context’s

Slide 15

Slide 15 text

v8 内置 API • v8/src/js/array.js => global.Array • utils.InstallFunctions

Slide 16

Slide 16 text

v8 内置 API • v8/src/js/math.js => global.Math • e.g. Math.atan2 => MathAtan2JS => src/runtime/ runtime-maths.cc => Runtime_MathAtan2 => std::atan2 => cmath => glibc => __ieee754_atan2 • utils.InstallFunctions

Slide 17

Slide 17 text

v8 内置 API • v8/src/js/i18n.js => global.Intl • ECMA-402 • Default: `small-icu` (English only) support • Intl.DateTimeFormat(['zh-CN']).format(new Date()) • Intl.DateTimeFormat(['en']).format(new Date())

Slide 18

Slide 18 text

Node.js ⽂文档记载的公开 API
 Node.js 的私有 API • lib/net.js -> internalNet (私有⼯工具⽅方法) • lib/dns.js
 -> C++ API:cares_wrap
 -> exports.resolve6
 -> queryAaaa
 -> Query
 -> ares_query
 -> deps/cares
 -> ares_send with callback

Slide 19

Slide 19 text

API ⼦子⽂文件 • lib/http.js
 -> const client = require('_http_client')
 -> 暴暴露辅助类 ClientRequest • lib/stream.js
 -> Stream.Transform = require('_stream_transform')
 -> const Duplex = require(‘_stream_duplex’)
 -> module.exports = Duplex;

Slide 20

Slide 20 text

JS API 转存为 C/C++ 代码 • Node采⽤用了了V8附带的js2c.py⼯工具,将所有内置的 JavaScript代码(src/node.js和lib/*.js)转换成C++ ⾥里里的数组,⽣生成node_natives.h头⽂文件 • 加载JavaScript核⼼心模块->标识符分析->直接定位到 内存中

Slide 21

Slide 21 text

v8 初探

Slide 22

Slide 22 text

重要概念念 • 隔离区 • 句句柄 • 上下⽂文

Slide 23

Slide 23 text

“隔离区” • class v8::Isolate {} • An isolate is a VM instance with its own heap • ⼀一个隔离区:⼀一个 v8 堆

Slide 24

Slide 24 text

句句柄之“局部句句柄” • template class Local {} • Because the garbage collector may move objects, it is unsafe to point directly to an object.

Slide 25

Slide 25 text

句句柄之“局部句句柄” • template class Local {} • An object reference managed by the v8 garbage collector. • A local handle is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works. • ⼀一个局部句句柄:⼀一个 v8 堆上的对象

Slide 26

Slide 26 text

句句柄之“持久句句柄” • Used when keeping a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes. • A UniquePersistent handle relies on C++ constructors and destructors to manage the lifetime of the underlying object. • A Persistent can be constructed with its constructor, but must be explicitly cleared with Persistent::Reset.

Slide 27

Slide 27 text

“句句柄区域” • class V8_EXPORT HandleScope {} • A stack-allocated class that governs a number of local handles. • a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope. • ⼀一个句句柄区域:N 个句句柄

Slide 28

Slide 28 text

~HandleScope, is called the handle scope is deleted. Objects referred to by handles within the deleted handle scope are eligible for removal in the next garbage collection

Slide 29

Slide 29 text

“上下⽂文”

Slide 30

Slide 30 text

“上下⽂文” • class V8_EXPORT Context {} • JavaScript provides a set of built-in utility functions and objects that can be changed by JavaScript code. • Creation of contexts implies creating the built-in objects and parsing the built-in JavaScript code (with cache) • each window and iframe in a browser can have its own fresh JavaScript environment.

Slide 31

Slide 31 text

“上下⽂文” • class V8_EXPORT Context {} • A sandboxed execution context with its own set of built-in objects and functions. • an execution environment that allows separate, unrelated, JavaScript code to run in a single instance of V8. You must explicitly specify the context in which you want any JavaScript code to be run.

Slide 32

Slide 32 text

v8 GC 特征 • “stop-the-world” • “generational” • “accurate”

Slide 33

Slide 33 text

v8 GC 特征 • “stop-the-world”
 stops program execution when performing a garbage collection cycle • “generational”
 processes only part of the object heap in most garbage collection cycles. This minimises the impact of stopping the application • “accurate”
 always knows exactly where all objects and pointers are in memory. This avoids falsely identifying objects as pointers which can result in memory leaks.

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

libuv 初探

Slide 36

Slide 36 text

libuv • supports Linux via epoll • supports Windows via Microsoft IOCP • supports Mac OS X via kqueue • same API on Linux, Windows, Mac • Little dependencies (On node-v0.9.0's version of libuv, the dependency on libev was removed)

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

#include #include #include int main() { uv_loop_t *loop = malloc(sizeof(uv_loop_t)); uv_loop_init(loop); uv_run(loop, UV_RUN_DEFAULT); uv_loop_close(loop); free(loop); return 0; }

Slide 40

Slide 40 text

“句句柄” • Handles represent long-lived objects capable of performing certain operations while active. • e.g.: a prepare handle gets its callback called once every loop iteration when active • e.g.: a TCP server handle get its connection callback called every time there is a new connection.

Slide 41

Slide 41 text

“句句柄” • 持久性对象 • 句句柄可以对应I/O设备,定时器,进程等 • 句句柄是不透明的数据结构,其中对应的类型 uv_TYPE_t中的type指定了了handle的使⽤用⽬目的

Slide 42

Slide 42 text

typedef struct uv_loop_s uv_loop_t; typedef struct uv_handle_s uv_handle_t; typedef struct uv_stream_s uv_stream_t; typedef struct uv_tcp_s uv_tcp_t; typedef struct uv_udp_s uv_udp_t; typedef struct uv_pipe_s uv_pipe_t; typedef struct uv_tty_s uv_tty_t; typedef struct uv_poll_s uv_poll_t; typedef struct uv_timer_s uv_timer_t; typedef struct uv_prepare_s uv_prepare_t; typedef struct uv_check_s uv_check_t; typedef struct uv_idle_s uv_idle_t; typedef struct uv_async_s uv_async_t; typedef struct uv_process_s uv_process_t; typedef struct uv_fs_event_s uv_fs_event_t; typedef struct uv_fs_poll_s uv_fs_poll_t; typedef struct uv_signal_s uv_signal_t;

Slide 43

Slide 43 text

“请求” • Requests represent (typically) short-lived operations. These operations can be performed over a handle • e.g.: write requests are used to write data on a handle • e.g.(standalone): getaddrinfo requests don’t need a handle they run directly on the loop

Slide 44

Slide 44 text

“请求” • 短暂性对象(通常只维持在⼀一个回调函数的时间) • 通常对映着句句柄上的⼀一个I/O操作 • ⽤用来在初始函数和回调函数之间,传递上下⽂文

Slide 45

Slide 45 text

typedef struct uv_req_s uv_req_t; typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; typedef struct uv_getnameinfo_s uv_getnameinfo_t; typedef struct uv_shutdown_s uv_shutdown_t; typedef struct uv_write_s uv_write_t; typedef struct uv_connect_s uv_connect_t; typedef struct uv_udp_send_s uv_udp_send_t; typedef struct uv_fs_s uv_fs_t; typedef struct uv_work_s uv_work_t;

Slide 46

Slide 46 text

事件循环 • tied to a single thread • all (network) I/O is performed on non-blocking sockets which are polled using the best mechanism available on the given platform • the loop will block waiting for I/O activity on sockets which have been added to the poller and callbacks will be fired indicating socket conditions (readable, writable hangup) so handles can read, write or perform the desired I/O operation.

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

线程池 • a global thread pool on which all loops can queue work on • runs blocking file I/O operations • runs DNS functions (getaddrinfo and getnameinfo) • runs User specified code via uv_queue_work()

Slide 49

Slide 49 text

(possibly) • linux AIO (supported in the kernel) • posix AIO (supported by linux, Mac OS X, BSD, solaris, AIX etc.) • Windows’ overlapped I/O

Slide 50

Slide 50 text

Thank you https://github.com/pmq20/