Chrome V8基础(一)
字数 1895 2025-08-09 22:00:49
Chrome V8 引擎基础解析
一、V8 引擎概述
Chrome V8 是一个由 Google 开发的高性能 JavaScript 引擎,采用 C++ 编写,用于执行 JavaScript 代码。它是 Google Chrome 浏览器的核心组件之一,也用于 Node.js 等环境。
1.1 V8 在 Chrome 架构中的位置
+------------------------------------------------------------------------------------------+
| Google Chrome |
| |
| +----------------------------------------+ +------------------------------+ |
| | Google V8 | | WebAPIs | |
| | +-------------+ +---------------+ | | | |
| | | Heap | | Stack | | | | |
| | | | | | | | | |
| | +-------------+ +---------------+ | | | |
| | | | | |
| +----------------------------------------+ +------------------------------+ |
| |
| +---------------------+ +---------------------------------------+ |
| | Event loop | | Task/Callback queue | |
| | | | | |
| +---------------------+ +---------------------------------------+ |
| +---------------------------------------+ |
| | Microtask queue | |
| | | |
| +---------------------------------------+ |
| |
+------------------------------------------------------------------------------------------+
二、V8 内存机制
V8 的内存管理是其核心功能之一,JavaScript 中声明的变量都由 V8 的内存机制管理,开发者无法直接管理这些内存。
2.1 内存分区
V8 的堆内存分为以下几个主要部分:
+-----------------------------------------------------------------------------------+
| Young Generation Old Generation Large Object space |
| +-------------+--------------+ +-----------+-------------+ +------------------+ |
| | NEW_SPACE | | MAP_SPACE | OLD_SPACE | | LO_SPACE | |
| +-------------+--------------+ +-----------+-------------+ +------------------+ |
| | from_Space | to_Space | |
| +-------------+--------------+ |
| +-------------+ +-----------+ +------------------+ |
| | NEW_LO_SPACE| | CODE_SPACE| | CODE_LO_SPACE | |
| +-------------+ +-----------+ +------------------+ |
| |
| Read-only |
| +--------------+ |
| | RO_SPACE | |
| +--------------+ |
+-----------------------------------------------------------------------------------+
- 新生代内存区 (Young Generation): 存放基本数据对象,区域小但回收频繁
- 老生代指针区 (Old Generation): 存放从新生代晋升过来的对象的指针
- 老生代数据区: 存放老生代对象的数据
- 大对象区 (Large Object space): 存放体积超过其他区大小的对象
- 代码区 (Code space): 存放 JIT 编译后的代码对象,唯一拥有执行权限的内存区
- Cell区、属性Cell区、Map区: 存放 Cell、属性Cell和Map,每个区域存放相同大小的元素
2.2 新生代内存回收 (Scavenge 算法)
新生代内存使用 Scavenge 算法进行回收,其核心思想是将内存一分为二:
ptrs from_space (evacuation) to_space
+----------+ +------------+
----->|marked: * | ---------->|marked: s | (s=survived)
+----------+ +------------+
|marked: | ----->|marked: s |
+----------+ / +------------+
----->|marked: * | ---- | |
+----------+ +------------+
|marked: | | |
+----------+ +------------+
|marked: | | |
+----------+ +------------+
特点:
- 内存分为两个 Semispace:From 空间和 To 空间
- 分配对象时使用 From 空间
- 垃圾回收时检查 From 空间中的存活对象,复制到 To 空间
- 回收完成后交换 From 和 To 空间角色
对象晋升条件:
- 对象已经经历过一次新生代清理
- To 空间使用超过 25%
2.3 老生代内存回收
老生代内存主要使用 Mark-Sweep 和 Mark-Compact 结合的方式进行回收:
Page 1 FreeList Page 1
+----------+ +--------------+ +------------+
|marked: * |---\ | Size 1 | --------|marked: s |
+----------+ \ | +----------+ | / +------------+
|marked: | ---|>|__________| | / -|marked: s |
+----------+ | |__________|<|-- / +------------+
|marked: * |--\ | |__________| | / | |
+----------+ \ | Size 2 | / +------------+
|marked: | \ | +----------+ | / | |
+----------+ ---|>|__________|<|------- +------------+
|marked: | | |__________| | | |
+----------+ | |__________| | +------------+
+--------------+
-
Mark-Sweep (标记清除):
- 标记阶段:遍历堆中所有对象,标记存活对象
- 清除阶段:清除未被标记的对象
- 优点:效率高(只处理死亡对象)
- 缺点:产生内存碎片
-
Mark-Compact (标记整理):
- 在 Mark-Sweep 基础上增加压缩步骤
- 让存活对象尽可能往内存区域前面靠
- 优点:避免内存碎片
- 缺点:效率比 Mark-Sweep 低
-
惰性清理: GC 延迟清理死掉的对象,根据需要清理
三、V8 核心概念
3.1 隔离实例 (Isolate)
Isolate 是 V8 引擎的实例,包含完全独立的各种状态(堆管理、垃圾回收等)。一个实例生成的任何对象不能在另一个实例中使用。
// 创建 Isolate 实例
v8::Isolate::CreateParams create_params;
v8::Isolate* isolate = v8::Isolate::New(create_params);
3.2 上下文 (Context)
Context 定义 JavaScript 执行环境,相当于沙箱化的执行上下文环境:
v8::Isolate* isolate = ...;
v8::Local<v8::Context> context = v8::Context::New(isolate);
3.3 脚本 (Script)
Script 对象包含已编译的 JavaScript 代码,与 Context 绑定:
v8::Local<v8::Context> context = ...;
v8::Local<v8::String> source = 一段JavaScript代码;
// 编译
v8::Local<v8::Value> result = v8::Script::Compile(context, source).ToLocalChecked();
// 执行
v8::Local<v8::Value> result = Script->Run(context).ToLocalChecked();
四、句柄 (Handle) 系统
句柄是 V8 中的重要概念,提供对堆内存中 JavaScript 数据对象的引用。GC 会更新句柄引用,确保对象移动后仍能正确访问。
4.1 句柄类型
- 本地句柄 (v8::Local): 存在于栈内存中,生命周期由句柄作用域决定
- 持久句柄 (v8::Persistent): 提供堆内存中对象的长期引用
- 永生句柄 (v8::Eternal): 程序生命周期内不会被删除
- 待实本地句柄 (MaybeLocal): 可能为空的本地句柄
4.2 本地句柄 (Local)
template <class T> class Local {
private:
T* val_
};
特点:
- 通过
.访问句柄方法 - 通过
*和->操作符访问对象实体 - 可使用
As或Cast进行类型转换
4.3 持久句柄 (Persistent)
持久句柄分为:
- 一般持久句柄 (v8::Persistent)
- 唯一持久句柄 (v8::UniquePersistent)
创建持久句柄:
Local<Number> local = Number::New(isolate, 2333);
Persistent<Number> persistent_handle(isolate, local);
4.4 待实本地句柄 (MaybeLocal)
用于处理可能返回空句柄的情况:
MaybeLocal<String> s = x.ToString();
if(!s.IsEmpty()){
Local<String> _s = s.ToLocalChecked();
}
五、总结
V8 引擎通过精细的内存管理和高效的垃圾回收算法实现了 JavaScript 的高性能执行。其核心特点包括:
- 分代式垃圾回收:新生代使用 Scavenge 算法,老生代使用 Mark-Sweep 和 Mark-Compact
- 隔离实例机制:确保不同实例状态完全独立
- 灵活的句柄系统:管理 JavaScript 对象的生命周期
- 高效的执行环境:通过 JIT 编译和优化的内存管理提升性能
理解这些基础概念对于深入掌握 V8 工作原理和浏览器安全机制至关重要。