7. 关键设计决策
这一篇用于把前面的知识点串成“为什么 V8 要这样设计”。
为什么要分层执行
冷代码不值得重度优化,热代码才值得投入编译成本。
所以 V8 用 Ignition 保启动,用 Sparkplug 快速提速,用 Maglev / Turbofan 处理热点代码。这是在 启动速度、内存、峰值性能 之间做平衡。
为什么要分代 GC
大部分对象很快死亡。把新对象放在新生代,可以用更便宜的方式频繁回收;活得久的对象再晋升到老生代,减少重复搬迁成本。
为什么需要写屏障
GC 执行时,JS 代码可能还在修改对象引用。写屏障用来维护跨代引用和增量标记正确性。
没有写屏障,年轻代 GC 可能漏掉老年代指向新生代的对象;增量标记也可能因为引用变化而误回收对象。
为什么要指针压缩
JS 堆里引用非常多,64 位指针会带来明显内存开销。指针压缩用 32 位偏移表示堆内引用,换取更低内存占用和更好的缓存表现。
代价是地址布局和安全机制更复杂。
为什么 Context 需要 global proxy
浏览器需要隔离不同页面、iframe、扩展脚本等全局环境。global proxy 让宿主可以代理和控制全局对象,同时不破坏 V8 内部对真实 global object 的假设。
为什么微任务策略由嵌入方控制
V8 是引擎,不是完整浏览器或 Node。不同宿主对“什么时候清空微任务队列”的定义不同,所以 V8 提供策略,宿主负责接入自己的事件循环。
总结
V8 的核心设计都在做权衡:执行分层平衡启动和性能,分代 GC 平衡吞吐和停顿,写屏障保证并发 GC 正确性,指针压缩降低内存,Context 和微任务策略服务嵌入场景。