跳到主要内容
预计阅读 37 分钟

浏览器篇 | 多进程架构

前言

你有没有想过,为什么 Chrome 浏览器打开几个标签页后,任务管理器里就多了一堆进程?为什么一个标签页崩溃了,其他标签页还能正常使用?为什么浏览器比以前的 IE 安全了那么多?

这些问题的答案,都指向同一个关键词:多进程架构

在前端面试中,“浏览器的多进程架构”是一个非常有区分度的考点。它不考你写代码的能力,而是考你对浏览器底层运行机制的理解深度。能把这个话题讲清楚的人,在面试官眼里至少是”认真研究过浏览器原理”的。

本章我们就来系统拆解 Chrome 的多进程架构:有哪些进程、每个进程负责什么、渲染进程内部有哪些线程、站点隔离是怎么回事、以及为什么选择多进程而不是多线程。


诊断自测

Q1:Chrome 浏览器至少有哪几类进程?各负责什么?

点击查看答案

Chrome 至少有以下几类进程:

  • Browser Process(浏览器主进程):管理地址栏、书签、前进/后退,负责网络请求、文件访问等特权操作
  • Renderer Process(渲染进程):负责解析 HTML/CSS/JS,渲染页面内容。每个标签页(或每个站点)通常有独立的渲染进程
  • GPU Process(GPU 进程):负责 GPU 相关任务,如页面合成、CSS 动画、WebGL
  • Plugin Process(插件进程):运行浏览器插件(如 Flash,已淘汰)
  • 还有 Utility Process、Extension Process 等辅助进程

Q2:进程和线程的核心区别是什么?

点击查看答案

进程是操作系统分配资源的基本单位,每个进程有独立的内存空间。进程之间相互隔离,一个进程崩溃不会影响其他进程,但进程间通信(IPC)开销较大。

线程是 CPU 调度的基本单位,同一进程内的线程共享该进程的内存空间。线程间通信效率高(共享内存),但一个线程崩溃可能导致整个进程崩溃。

Q3:渲染进程的主线程负责哪些工作?为什么说主线程是”瓶颈”?

点击查看答案

渲染进程的主线程负责:解析 HTML/CSS、执行 JavaScript、计算样式、布局(Layout)、绘制(Paint)。几乎所有核心工作都在主线程上串行执行。当 JS 执行时间过长时,会阻塞布局和绘制,导致页面卡顿,所以主线程是渲染性能的”瓶颈”。


一、先搞清楚:进程 vs 线程

在聊多进程架构之前,先明确两个基础概念。

进程(Process)

进程是操作系统分配资源的最小单位。 每个进程有自己独立的内存空间、代码、数据。进程之间是隔离的——一个进程不能直接读写另一个进程的内存。

你可以把进程想象成一栋独立的房子:每栋房子有自己的水电气(资源),互不干扰。一栋房子着火了(崩溃),不会影响隔壁的房子。

线程(Thread)

线程是 CPU 调度的最小单位。 一个进程可以包含多个线程,它们共享进程的内存空间和资源。

线程就像同一栋房子里的多个房间:它们共用水电气(共享内存),沟通方便(不需要 IPC),但如果其中一个房间的电线短路引发火灾(线程崩溃),整栋房子都可能被烧毁(进程崩溃)。

对比表

特性进程线程
内存空间独立共享所在进程的内存
通信方式IPC(管道、共享内存、消息等)直接访问共享变量
创建/销毁开销
一个崩溃的影响不影响其他进程可能导致整个进程崩溃
安全性高(隔离)低(共享内存可能导致竞争)

二、Chrome 的多进程架构

早期的浏览器(比如 IE6-8)是单进程的:所有标签页、插件、浏览器 UI 都跑在一个进程里。结果就是——一个标签页挂了,整个浏览器一起挂;一个恶意脚本能影响所有打开的页面;一个插件崩溃就带走整个浏览器。

Chrome 从 2008 年诞生之初就采用了多进程架构,彻底解决了这些问题。

四大核心进程

1. Browser Process(浏览器主进程)

只有一个,是整个浏览器的”管理者”。职责包括:

  • UI 管理:地址栏、书签栏、前进/后退按钮、标签栏
  • 网络请求:发起和管理 HTTP 请求(通过 Network Thread)
  • 文件访问:读写磁盘上的文件(下载、缓存等)
  • 进程管理:创建和销毁其他进程(渲染进程、GPU 进程等)
  • 权限管理:决定哪个渲染进程可以访问哪些资源

Browser Process 拥有操作系统层面的特权,而渲染进程运行在沙箱中,没有这些权限。这是安全架构的核心。

2. Renderer Process(渲染进程)

最核心的进程,负责页面内容的呈现。职责包括:

  • 解析 HTML → DOM 树
  • 解析 CSS → CSSOM 树
  • 执行 JavaScript(通过 V8 引擎)
  • 计算布局(Layout)
  • 绘制(Paint)
  • 合成(部分工作交给合成线程)

每个标签页通常有自己独立的渲染进程(站点隔离策略下更精确的说法是”每个站点一个渲染进程”,后面会详细讲)。这就是为什么一个标签页卡死了,其他标签页不受影响。

渲染进程运行在**沙箱(Sandbox)**中,不能直接访问操作系统资源(文件、网络等)。所有特权操作必须通过 IPC 请求 Browser Process 代为执行。这极大地提升了安全性——即使渲染进程被恶意代码攻破,攻击者也很难突破沙箱。

3. GPU Process(GPU 进程)

负责所有 GPU 相关的任务:

  • 页面的合成(Compositing)
  • CSS 动画和 transform 的 GPU 加速
  • WebGL 渲染
  • 视频解码

GPU 进程只有一个,为所有渲染进程提供服务。为什么 GPU 需要独立进程?因为 GPU 操作涉及硬件访问,把它隔离出来可以避免 GPU 驱动的 bug 导致整个浏览器崩溃。

4. Plugin Process(插件进程)

运行浏览器插件(如曾经的 Flash Player)。每个插件一个进程。

随着 Flash 的退场和 Chrome 扩展转向 Web 技术,传统意义上的 Plugin Process 已经很少见了。但 Chrome 扩展(Extension)仍然有自己的进程。

其他进程

  • Utility Process:处理一些零散的任务,比如解码图片、解压文件
  • Network Service:在新版 Chrome 中,网络请求被抽成了独立的服务进程
  • Storage Service:管理存储(IndexedDB、Cache API 等)
  • Audio Service:处理音频

架构示意

┌────────────────────────────────────────────┐
│              Browser Process               │
│  ┌──────┐ ┌──────────┐ ┌───────────────┐  │
│  │ UI   │ │ Network  │ │ Storage/File  │  │
│  │Thread│ │ Thread   │ │ Thread        │  │
│  └──────┘ └──────────┘ └───────────────┘  │
└──────────────────┬─────────────────────────┘
                   │ IPC
    ┌──────────────┼──────────────┐
    │              │              │
    ▼              ▼              ▼
┌────────┐  ┌────────┐    ┌────────────┐
│Renderer│  │Renderer│    │ GPU Process │
│Process │  │Process │    │            │
│(Tab A) │  │(Tab B) │    └────────────┘
└────────┘  └────────┘

三、渲染进程内部的线程

虽然 Chrome 使用多进程架构,但在每个渲染进程内部,又有多个线程协同工作。这部分是理解浏览器渲染性能的关键。

3.1 主线程(Main Thread)

渲染进程中最重要、也是最”忙”的线程。它负责:

  • 解析 HTML:构建 DOM 树
  • 解析 CSS:构建 CSSOM 树
  • 执行 JavaScript:V8 引擎跑在主线程上
  • 计算样式:将 CSS 规则应用到 DOM 节点
  • 布局(Layout):计算每个元素的位置和大小
  • 绘制(Paint):生成绘制指令列表

注意:主线程是单线程的,所有这些工作都是串行执行的。这意味着如果 JS 执行时间太长,后面的布局和绘制就会被阻塞,页面就会卡顿。

主线程的工作流:
JS 执行 → 样式计算 → Layout → Paint → (提交给合成线程)
   ↑                                        │
   └────────── 一帧(约 16.7ms @60fps)──────┘

如果你的 JS 执行花了 50ms,那这一帧就会超时,用户就会感到卡顿。这就是为什么我们要避免”长任务(Long Task)“——超过 50ms 的任务就算长任务了。

3.2 合成线程(Compositor Thread)

合成线程负责将主线程生成的绘制指令合成最终的页面画面。

关键特性:合成线程独立于主线程运行。 这意味着即使主线程被 JS 阻塞了,合成线程仍然可以处理一些工作,比如:

  • 滚动:页面滚动由合成线程直接处理(如果不涉及 JS 事件监听),所以即使主线程很忙,页面也能流畅滚动
  • CSS 动画transformopacity 的动画可以完全在合成线程中处理,不需要主线程参与

这也解释了为什么用 transform 做动画比用 left/top 更流畅——后者需要主线程计算布局,前者只需要合成线程重新合成。

3.3 光栅化线程(Raster Thread)

合成线程将页面分成多个图块(Tiles),然后交给光栅化线程将每个图块转换成位图(像素数据)。

Chrome 通常有多个光栅化线程并行工作,加速页面的光栅化过程。光栅化的结果会被存储在 GPU 内存中。

3.4 Worker 线程

除了上述浏览器内部的线程,开发者还可以通过 Web API 创建自己的线程:

  • Web Worker:可以在后台线程中运行 JS,不阻塞主线程
// main.js
const worker = new Worker('heavy-task.js');
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => {
  console.log('计算结果:', e.data);
};

// heavy-task.js
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};
  • Service Worker:运行在独立线程中,充当网页和网络之间的代理,可以拦截请求、管理缓存
  • Shared Worker:可以被多个页面共享的 Worker

Worker 线程和主线程之间通过 postMessage 通信(本质上也是消息传递,类似 IPC),不能直接访问 DOM。

线程协作流程

一次完整的页面渲染,各线程的协作流程:

主线程                    合成线程              光栅线程        GPU 进程
  │                         │                    │               │
  │──── 样式计算 ────►      │                    │               │
  │──── Layout ────►        │                    │               │
  │──── Paint ────►         │                    │               │
  │ (生成绘制指令)           │                    │               │
  │                         │                    │               │
  │── commit ──────────►    │                    │               │
  │                    分割为 Tiles               │               │
  │                         │── rasterize ──►    │               │
  │                         │                 生成位图            │
  │                         │◄── 位图完成 ───    │               │
  │                    合成帧 (draw quads)        │               │
  │                         │── display ─────────────────────►   │
  │                         │                    │          显示到屏幕

四、站点隔离(Site Isolation)

什么是站点隔离

早期 Chrome 的策略是”一个标签页一个渲染进程”。但在 2018 年,Chrome 67 引入了站点隔离(Site Isolation),将粒度从”标签页”细化到了”站点(Site)”。

站点隔离意味着:不同站点的页面,即使在同一个标签页内(比如通过 iframe 嵌入),也会运行在不同的渲染进程中。

<!-- example.com 的页面 -->
<iframe src="https://ads.thirdparty.com/banner"></iframe>

在站点隔离策略下,example.comads.thirdparty.com 会运行在不同的渲染进程中,即使它们在同一个标签页内显示。

为什么需要站点隔离

安全。主要是为了防御两类攻击:

  1. Spectre 漏洞:2018 年曝出的 CPU 漏洞,允许恶意代码通过侧信道攻击读取同一进程中的内存数据。如果两个不同站点在同一进程中,恶意站点可能通过 Spectre 窃取另一个站点的数据(比如银行页面的敏感信息)。站点隔离确保不同站点在不同进程中,从操作系统层面杜绝了这种攻击。

  2. 一般的安全隔离:即使没有 Spectre,把不同站点隔离在不同进程中,也能防止一个被攻破的渲染进程影响其他站点的数据。

“站点”的定义

站点(Site)= 协议(scheme)+ 注册域名(eTLD+1)。

https://mail.google.com   → 站点是 https://google.com
https://docs.google.com   → 站点是 https://google.com(同站点)
https://www.example.com   → 站点是 https://example.com
http://www.example.com    → 站点是 http://example.com(和 https 不同站点!)

注意:mail.google.comdocs.google.com同站点的,所以它们可能共享同一个渲染进程。

站点隔离的代价

站点隔离提升了安全性,但也增加了资源消耗:

  • 更多进程:每个站点一个进程,意味着更多的内存占用
  • 跨进程通信:iframe 和父页面如果在不同进程中,通信需要通过 IPC,增加延迟
  • 内存消耗:Chrome 官方数据显示,站点隔离会增加约 10-13% 的内存使用

这也是为什么 Chrome 在移动端(内存更紧张)对站点隔离有更保守的策略。


五、为什么选择多进程而不是多线程?

这是面试中经常出现的一个”追问”。既然多进程比多线程消耗更多资源,为什么 Chrome 还要选择多进程?

1. 稳定性:崩溃隔离

多线程共享内存空间,一个线程的 crash(比如访问了非法内存地址)会导致整个进程崩溃。在多进程架构下,一个渲染进程崩溃只会影响对应的标签页,浏览器可以显示一个”Aw, Snap!”错误页面,其他标签页照常工作。

多线程架构:
  Tab A 崩溃 → 整个浏览器崩溃 → Tab B、C、D 全部丢失

多进程架构:
  Tab A 崩溃 → 只有 Tab A 显示错误页面 → Tab B、C、D 不受影响

2. 安全性:沙箱隔离

操作系统的安全机制是基于进程的。你可以给一个进程设置权限限制(沙箱),但很难给进程内部的某个线程单独设置权限。

Chrome 的渲染进程运行在沙箱中,没有权限:

  • 直接读写文件系统
  • 直接发起网络请求
  • 直接访问剪贴板
  • 直接调用操作系统 API

所有这些操作都必须通过 IPC 向 Browser Process 请求。即使渲染进程被攻破(比如通过 JS 漏洞),攻击者也被困在沙箱里,无法危害系统。

在多线程架构下,所有线程共享同一份权限,一个线程被攻破就意味着整个进程的权限泄露。

3. 资源管理:独立回收

多进程架构下,关闭一个标签页就是结束一个进程。操作系统会完整回收该进程的所有资源——内存、文件句柄、网络连接等。不会有内存泄漏残留。

在多线程架构下,关闭一个标签页只是结束一些线程。由于线程共享内存,要彻底清理干净非常困难,容易出现内存泄漏——这正是早期浏览器越用越慢、越用越占内存的原因之一。

4. 并行利用多核 CPU

虽然多线程也能利用多核 CPU,但多进程的并行粒度更大,更适合浏览器这种”多个独立页面并行运行”的场景。操作系统的进程调度器也能更好地分配 CPU 时间。

多进程的代价

当然,多进程也有代价:

  • 内存占用高:每个进程都有自己的 V8 实例、DOM 拷贝等基础设施
  • 启动时间长:创建新进程比创建新线程慢
  • IPC 开销:进程间通信比线程间通信慢

Chrome 团队也在不断优化这些问题。比如通过”进程合并”策略,在设备资源紧张时,将多个同站点的标签页合并到同一个渲染进程中。


六、从输入 URL 到页面呈现:进程视角

把多进程架构的知识串起来,我们来看看从输入 URL 到看到页面的过程中,各个进程是怎么协作的:

1. 用户输入 URL(Browser Process)

Browser Process 的 UI 线程 收到用户输入,判断是 URL 还是搜索关键词。

2. 发起网络请求(Browser Process)

UI 线程通知 Network 线程发起网络请求。Network 线程处理 DNS 解析、TCP 连接、TLS 握手、发送 HTTP 请求。

3. 读取响应(Browser Process)

Network 线程收到响应后:

  • 检查 Content-Type:如果是 HTML,准备交给渲染进程;如果是文件下载,交给下载管理器
  • 进行安全检查(SafeBrowsing)
  • 进行 CORB(Cross-Origin Read Blocking)检查

4. 创建/选择渲染进程(Browser Process)

Browser Process 为这个页面创建(或选择已有的)渲染进程。

5. 提交导航(Browser Process → Renderer Process)

Browser Process 通过 IPC 向渲染进程发送”提交导航”的消息,同时传递 HTML 数据流。

6. 解析和渲染(Renderer Process)

渲染进程的主线程开始解析 HTML、构建 DOM、解析 CSS、执行 JS、Layout、Paint。

渲染进程的合成线程将 Paint 的结果合成为帧,提交给 GPU Process。

7. 显示(GPU Process)

GPU Process 将合成的帧显示到屏幕上。

用户输入 → Browser Process → Network → 安全检查 → 选择 Renderer
              ↓ IPC
         Renderer Process → 解析/渲染 → 合成
              ↓ IPC
         GPU Process → 显示到屏幕

常见误区

误区一:“一个标签页就是一个进程”

在站点隔离之前,大致是这样。但站点隔离启用后,一个标签页可能有多个进程(主页面一个,每个跨站 iframe 一个),而同一站点的多个标签页在资源紧张时可能共享一个进程。准确说法是”Chrome 使用以站点为粒度的进程分配策略”。

误区二:“JS 是单线程的,所以浏览器也是单线程的”

JS 的执行确实是单线程的(在主线程上),但浏览器本身是多进程多线程的。渲染进程内部就有主线程、合成线程、光栅线程等多个线程。而且你可以通过 Web Worker 创建额外的 JS 执行线程。说”JS 是单线程”没问题,但说”浏览器是单线程”就大错特错了。

误区三:“多进程比多线程一定好”

多进程在安全性和稳定性上确实优于多线程,但代价是更高的内存占用和 IPC 开销。在资源受限的设备(比如低端手机)上,Chrome 会主动减少进程数量,将多个标签页合并到同一个渲染进程中。没有”一定好”的架构,只有针对具体场景的权衡。

误区四:“合成线程可以完全替代主线程做渲染”

合成线程只能处理不需要重新布局和绘制的操作(比如 transform、opacity 动画和滚动)。任何需要改变 DOM、计算样式、重新布局的操作,都必须回到主线程。合成线程是主线程的”助手”,而不是”替代品”。


小结

本章从进程和线程的基本概念出发,系统梳理了 Chrome 的多进程架构。

核心要点

  1. Chrome 采用多进程架构:Browser Process 管理全局,Renderer Process 负责页面渲染,GPU Process 处理图形,各司其职
  2. 渲染进程运行在沙箱中:不能直接访问系统资源,所有特权操作通过 IPC 委托 Browser Process
  3. 渲染进程内部有多个线程:主线程(解析/JS/布局/绘制)、合成线程(合成/滚动/动画)、光栅线程(图块光栅化)
  4. 主线程是瓶颈:JS 执行、布局、绘制都在主线程串行完成,长任务会导致卡顿
  5. 站点隔离:不同站点运行在不同进程中,防御 Spectre 等安全威胁
  6. 选择多进程的原因:崩溃隔离、沙箱安全、资源回收、多核利用
  7. Web Worker:开发者可以创建额外的 JS 线程,分担主线程压力

本章思维导图

浏览器:多进程架构
  • 基础概念
    • 进程:独立内存空间,隔离性好,开销大
    • 线程:共享内存,通信快,隔离性差
  • Chrome 进程
    • Browser Process:UI、网络、文件、进程管理
    • Renderer Process:HTML/CSS/JS 解析、布局、绘制
    • GPU Process:合成、动画、WebGL
    • Plugin Process:插件(已逐渐淘汰)
    • 其他:Utility、Network Service 等
  • 渲染进程内部线程
    • 主线程:解析、JS 执行、样式计算、Layout、Paint
    • 合成线程:合成、滚动、transform/opacity 动画
    • 光栅线程:图块 → 位图
    • Worker 线程:Web Worker、Service Worker
  • 站点隔离
    • 不同站点不同进程(即使在同一标签页)
    • 防御 Spectre 等侧信道攻击
    • 站点 = 协议 + eTLD+1
    • 代价:更多内存,更多 IPC
  • 为什么多进程
    • 崩溃隔离
    • 沙箱安全
    • 资源回收
    • 多核利用
    • 代价:内存、启动时间、IPC

练习挑战

第一题(⭐ 基础):判断对错

以下说法哪些是正确的?

A. Chrome 的每个标签页一定有独立的渲染进程 B. 渲染进程不能直接发起网络请求 C. Web Worker 运行在主线程上 D. transform 动画可以在合成线程上完成,不需要主线程参与 E. GPU Process 只有一个,服务于所有渲染进程

点击查看答案与解析
  • A 错误:不是”一定”。同站点的多个标签页在资源紧张时可能共享渲染进程;一个标签页内如果有跨站 iframe,可能有多个渲染进程
  • B 正确:渲染进程在沙箱中,网络请求由 Browser Process 的 Network 线程处理
  • C 错误:Web Worker 运行在独立的线程中,这正是它的意义——不阻塞主线程
  • D 正确:transform 和 opacity 动画可以完全由合成线程处理
  • E 正确:GPU Process 全局只有一个

正确答案:B、D、E

第二题(⭐⭐ 进阶):分析进程分配

假设用户打开了以下页面:

  • Tab 1: https://mail.google.com
  • Tab 2: https://docs.google.com
  • Tab 3: https://www.example.com,其中嵌入了 <iframe src="https://ads.adserver.com/banner">

在启用站点隔离的情况下,至少需要几个渲染进程?分别负责什么?

点击查看答案与解析

至少需要 3 个渲染进程

  1. 进程 A:负责 https://mail.google.comhttps://docs.google.com。虽然它们是不同的标签页,但它们是同站点的(都属于 https://google.com),可以共享渲染进程。
  2. 进程 B:负责 Tab 3 中 https://www.example.com 的主页面。
  3. 进程 C:负责 Tab 3 中 https://ads.adserver.com 的 iframe。虽然 iframe 在 Tab 3 内部显示,但它和 example.com 不是同站点,所以需要独立的渲染进程。

除此之外,还有 Browser Process、GPU Process 等,但这里只问渲染进程的数量。

第三题(⭐⭐⭐ 综合):架构设计思考

假设你要设计一个浏览器的标签页管理策略。设备内存有限(2GB),用户可能同时打开 20 个标签页。你需要在”性能/安全/资源占用”之间做权衡。请描述你的进程分配策略,包括:

  1. 什么情况下创建新进程
  2. 什么情况下复用已有进程
  3. 如何处理内存压力
点击查看答案与解析

参考策略(类似 Chrome 在低端设备上的做法):

1. 创建新进程的条件:

  • 打开不同站点的新标签页时,创建新渲染进程
  • 跨站 iframe 尽量隔离(安全优先)
  • 用户交互频繁的前台标签页优先获得独立进程

2. 复用已有进程的条件:

  • 同站点的标签页共享渲染进程(如同一个域名下的多个页面)
  • 当进程总数超过阈值(比如根据内存动态计算,2GB 设备约 10-15 个渲染进程),开始将新的同站点标签页合并到已有进程
  • 后台标签页(长时间未交互)可以被”冻结”甚至”丢弃”——保留 URL 等元信息,释放渲染进程

3. 内存压力处理:

  • 监控系统可用内存。当内存紧张时:
    • 先丢弃后台标签页的渲染进程(用户切回来时重新加载)
    • 合并同站点的标签页到同一进程
    • 压缩后台标签页的内存(V8 的 Memory Pressure 通知)
    • 最后手段:提示用户关闭标签页

这个策略的核心思想是:安全底线不动摇(跨站隔离),性能在资源允许时最大化(独立进程),资源紧张时优雅降级(合并/冻结/丢弃)。


自我检测

  • 能说清楚进程和线程的区别,以及它们在安全性、稳定性、通信方式上的差异
  • 能列出 Chrome 的四大核心进程及各自的职责
  • 能说出渲染进程内部的主要线程(主线程、合成线程、光栅线程)及各自的分工
  • 能解释为什么主线程是渲染性能的”瓶颈”
  • 能说清楚站点隔离的含义、目的和代价
  • 能从稳定性、安全性、资源管理三个角度解释为什么 Chrome 选择多进程而不是多线程
  • 能描述从输入 URL 到页面呈现的过程中,各个进程是如何协作的
  • 能说出 Web Worker 的作用和它与主线程的通信方式

购买课程解锁全部内容

大厂前端面试通关:71 篇构建完整知识体系

¥89.90