3、WebKit 核心架构总览:WebCore 与 JavaScriptCore、渲染引擎与 JS 引擎的分工、多进程架构
聊到 WebKit,很多人第一反应是「浏览器内核」。但说实话,这个说法太笼统了。我做了这么多年 Android 系统开发,见过不少同事把 WebKit 当成一个黑盒来用,出了问题就抓瞎。今天咱们就把这个黑盒拆开,看看里面到底是怎么运作的。
WebKit 的核心架构,说白了就是两大引擎 + 多进程分工。两大引擎分别是 WebCore 和 JavaScriptCore。多进程架构则是 Browser、GPU、Renderer 三个进程各司其职。咱们一个一个说。
3.1 WebCore 与 JavaScriptCore:双核驱动
WebCore 是 WebKit 的渲染引擎,负责解析 HTML、CSS,构建 DOM 树和渲染树,最终把页面画出来。JavaScriptCore 呢,就是 JS 引擎,负责执行 JavaScript 代码。这两个东西是独立工作的,但必须紧密配合。
我刚开始接触 WebKit 时,有个误区:以为 JS 引擎是渲染引擎的一部分。其实不是。它们俩是平级的,通过绑定层(Binding Layer)来通信。你可以把 WebCore 想象成工厂的生产线,JavaScriptCore 是生产线上的机器人。机器人(JS)可以指挥生产线(WebCore)干活,但生产线本身有自己的节奏。
为什么会这样设计?你想想看,如果 JS 引擎和渲染引擎耦合在一起,那执行一段耗时的 JS 代码时,整个页面就卡死了。分开之后,JS 引擎可以异步执行,渲染引擎该画就画,互不影响。当然,实际上还有更复杂的同步机制,但大原则就是这样。
3.2 渲染引擎与 JS 引擎的分工
咱们来细化一下分工。WebCore 内部有几个关键模块:
- HTML 解析器: 把 HTML 文本解析成 DOM 树
- CSS 解析器: 解析 CSS,生成样式规则
- 布局引擎: 计算每个元素的位置和大小
- 绘制引擎: 把布局结果绘制到屏幕上
JavaScriptCore 呢,主要负责:
- 词法/语法分析: 把 JS 源码变成抽象语法树(AST)
- 即时编译(JIT): 把热点代码编译成机器码,提升执行速度
- 垃圾回收: 自动管理内存,回收不再使用的对象
这里有个关键点:DOM 操作。JS 代码经常要操作 DOM,比如 document.getElementById。这个操作其实是 JS 引擎通过绑定层调用 WebCore 的接口。每次 DOM 操作都有一定的开销,所以我在项目中一直强调:减少 DOM 操作,批量更新。
offsetHeight。每次读取都会触发强制回流(Forced Reflow),WebCore 不得不重新计算布局。后来改成缓存这些值,性能提升很明显。
为了更直观地理解,我画了一张架构图:
3.3 多进程架构:Browser / GPU / Renderer
早期的浏览器是单进程的,一个页面崩溃整个浏览器都挂了。后来 Chrome 率先引入了多进程架构,WebKit 也跟进。在 Android 平台上,WebView 默认也是多进程模式。
三个核心进程的分工如下:
| 进程 | 职责 | 典型问题 |
|---|---|---|
| Browser Process | 管理 UI、地址栏、网络请求、文件访问 | OOM(内存不足)时容易崩溃 |
| Renderer Process | 每个标签页一个,负责解析、渲染、执行 JS | 沙箱隔离,崩溃不影响其他进程 |
| GPU Process | 负责图形合成、硬件加速 | 驱动兼容性问题,黑屏 |
这里有个细节:Renderer Process 是运行在沙箱里的。它不能直接访问文件系统或网络,必须通过 Browser Process 转发。这样做是为了安全——即使某个页面被攻破,攻击者也拿不到系统权限。
android:process 属性配置的。如果你在应用中同时使用多个 WebView,记得考虑进程间通信(IPC)的开销。我曾经遇到过一个案例,多个 WebView 同时加载大页面,导致 Browser Process 的 Binder 线程池耗尽,页面加载超时。
进程间通信主要靠 IPC(Inter-Process Communication)。WebKit 使用 Chromium 的 IPC 框架,基于 Mojo 协议。Renderer Process 把绘制指令序列化,通过 IPC 发给 GPU Process,GPU Process 再调用 OpenGL ES 或 Vulkan 进行渲染。
你可能会问:为什么不直接在 Renderer Process 里渲染?原因有两个:一是安全,二是稳定性。GPU 驱动经常有 bug,如果 Renderer Process 直接调用 GPU,一个驱动崩溃就能拖垮整个标签页。通过 GPU Process 隔离,驱动崩溃只影响合成,Renderer Process 可以重新发起请求。
onTrimMemory() 回调,在内存紧张时主动清理 GPU 缓存。这个优化让低端机的页面滚动流畅度提升了 30% 以上。
最后,用一张图总结多进程架构:
嗯,以上就是 WebKit 核心架构的全貌。WebCore 和 JavaScriptCore 各司其职,多进程架构保障了稳定性和安全性。理解这些基础,后面咱们聊渲染流程、JS 绑定、性能优化时,你就能知道每个环节到底发生在哪个进程、哪个模块里了。