浏览器进程
一、认识
1.1 什么是进程?
进程: 指在系统中正在运行的一个应用程序,程序一旦运行就是进程。或者更专业化来说:进程是指程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
1.2 什么是线程?
线程: 系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。进程——资源分配的最小单位,线程——程序执行的最小单位。
1.3 进程与线程的区别
- 因为进程拥有独立的堆栈空间和数据段,所以每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这对于多进程来说十分“奢侈”,系统开销比较大,而线程不一样,线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高,但是正由于进程之间独立的特点,使得进程安全性比较高,也因为进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。一个线程死掉就等于整个进程死掉。
- 体现在通信机制上面,正因为进程之间互不干扰,相互独立,进程的通信机制相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便。。
- 体现在CPU系统上面,线程使得CPU系统更加有效,因为操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
- 体现在程序结构上,举一个简明易懂的列子:当我们使用进程的时候,我们不自主的使用if else嵌套来判断pid,使得程序结构繁琐,但是当我们使用线程的时候,基本上可以甩掉它,当然程序内部执行功能单元需要使用的时候还是要使用,所以线程对程序结构的改善有很大帮助。
1.4 进程与线程之间的关系
- 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
- 资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
- 处理机分给线程,即真正在处理机上运行的是线程。
- 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
1.5 什么情况下使用进程? 什么情况下使用线程?
- 需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的
- 线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
- 因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程
- 并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求
- 需要更稳定安全时,适合选择进程;需要速度时,选择线程更好
二、Chrome 多进程架构

从图中可以看出,最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。
2.2 浏览器进程
浏览器进程 主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
2.2 渲染进程
渲染进程 核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。渲染进程包含的线程如下:
- GUI渲染线程
- 负责渲染页面,布局和绘制
- 页面需要重绘和回流时,该线程就会执行
- 与js引擎线程互斥,防止渲染结果不可预期
- JS引擎线程
- 负责处理解析和执行javascript脚本程序
- 只有一个JS引擎线程(单线程)
- 与GUI渲染线程互斥,防止渲染结果不可预期
- 事件触发线程
- 用来控制事件循环(鼠标点击、setTimeout、ajax等)
- 当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中
- 定时触发器线程
- setInterval与setTimeout所在的线程
- 定时任务并不是由JS引擎计时的,是由定时触发线程来计时的
- 计时完毕后,通知事件触发线程
- 异步http请求线程
- 浏览器有一个单独的线程用于处理AJAX请求
- 当请求完成时,若有回调函数,通知事件触发线程
当我们了解了渲染进程包含的这些线程后,我们思考两个问题:
-
为什么 javascript 是单线程的?
首先是历史原因,在创建
Javascript
这门语言时,多进程多线程的架构并不流行,硬件支持并不好。其次是因为多线程的复杂性,多线程操作需要加锁,编码的复杂性会增高。而且,如果同时操作DOM
,在多线程不加锁的情况下,最终会导致DOM
渲染的结果不可预期。 -
为什么 GUI 渲染线程与 JS 引擎线程互斥
这是由于
JavaScript
是可以操作DOM
的,如果同时修改元素属性并同时渲染界面(即 JS线程和UI线程同时运行), 那么渲染线程前后获得的元素就可能不一致了。因此,为了防止渲染出现不可预期的结果,浏览器设定GUI
渲染线程和JavaScript
引擎线程为互斥关系, 当JavaScript
引擎线程执行时GUI
渲染线程会被挂起,GUI
更新则会被保存在一个队列中等待JS引擎线程空闲时立即被执行。
2.3 GPU 进程
GPU 进程 其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
2.4 网络进程
网络进程 主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
2.5 插件进程
插件进程 主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
2.6 多进程问题
-
对于浏览器多进程的思考: 浏览器多进程模型提升了浏览器的稳定性、流畅性和安全性,但同样不可避免地带来了一些问题:
- 更高的资源占用 因为每个进程都会包含公共基础结构的副本(如 JavaScript 运行环境),这就意味着浏览器会消耗更多的内存资源。
- 更复杂的体系架构 浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了。
-
浏览器多进程的优势:
- 避免单个page crash影响整个浏览器
- 避免第三方插件crash影响整个浏览器
- 多进程充分利用多核优势
- 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性
三、未来面向服务的架构
为了解决更高的资源占用以及更复杂的体系架构的问题,在 2016 年,Chrome
官方团队使用“面向服务的架构”(Services Oriented Architecture,简称 SOA)的思想设计了新的 Chrome 架构。也就是说 Chrome
整体架构会朝向现代操作系统所采用的“面向服务的架构” 方向发展,原来的各种模块会被重构成独立的服务(Service),每个服务(Service)都可以在独立的进程中运行,访问服务(Service)必须使用定义好的接口,通过IPC来通信,从而构建一个更内聚、松耦合、易于维护和扩展的系统,更好实现 Chrome 简单、稳定、高速、安全的目标。
理解: 以前是每个页面需要若干进程完成各自的工作,现在是将各个页面通用的功能(视频、网络、渲染等)发布为系统服务,页面在需要的时候与相应的服务通信完成需要的功能。这起码把进程间的耦合从页面中分离出去了。如下图所示:

四、沉淀与思考
4.1 浏览器开启 2 个 Tab,它们是属于一个进程还是两个?
现代浏览器通常采用多进程架构来提高稳定性和安全性,一般来说,每个 Tab
都会有独立的渲染进程,这样即使某个 Tab
出现崩溃,也不会影响其他 Tab
。像 Google Chrome
、Microsoft Edge
等浏览器默认为每个 Tab
分配独立的渲染进程,实现沙箱隔离和更高的安全性与稳定性。因此,虽然大部分情况下两个独立的 Tab
会分别运行在两个进程中,但具体情况依赖于浏览器的架构和配置选项。