浅谈 Chrome 中的多进程架构

668 阅读6分钟

这是我参与8月更文挑战的第2天,活动详情查看: 8月更文挑战

序言

近期参加了掘金的八月更文挑战,于是决定来一个月不停歇的学习并且日更的挑战。最后选择了浏览器的工作原理这个方向进行学习,今天是这个内容的第一篇文章,我会将我学到的和碰到的疑惑进行讨论和讲述,希望能够起到一个巩固学习的作用,也希望能帮想要学习的小伙伴少走一些弯路。 今天我们要学习的是Chrome 中的 多进程架构,学完后可以知道 Chrome 浏览器中任务的执行流程。

线程与进程

我们先了解一下浏览器中,什么是 线程,什么 进程 。 例子1 : 假设现在浏览器要处理如下代码

let coolFish
let teacherGuo
let pingan = coolFish + teacherGuo

在解析这些代码的时候,我们可以分为四个任务:

  1. 任务1 :声明 coolFish。
  2. 任务2 :声明 teacherGuo。
  3. 任务3 :声明 pingan。
  4. 任务4 :计算 coolFish + teacherGuo 并赋值。

线程

在浏览器中,这个4个任务用 单线程 处理的话,会按顺序依次处理,一共需要四步。 ​

但是如果使用 多线程 的话,我们分为两步,第一步,声明变量。第二步,计算并且赋值。一共需要两步。 ​

通过对比,我们发现,多进程操作比单进程步骤要少,因此处理能力会大大提升。 ​

进程

进程是一个程序的运行实例,也就是说一个程序启动时,操作系统会为该程序创建一块内存,用来运行该程序中的操作,我们把这个运行的环境叫做 进程。

线程是不能单独存在的,由进程来启动和管理的,为了方便理解,可以参照下图。

线程.png

由图中可知,进程是老板,线程是工人,进程管理线程,让线程执行任务,但是他们有以下 4个特点。 ​

  1. 进程中的任意个线程执行出错,整个进程都会奔溃

例如上图中,假设任务1出错了,那么当前进程则会直接崩溃,任务2,任务3也会消失。

  1. 线程之间共享进程中的数据。

同一个进程中,他们的数据文件都是共享的,所有进程都可以进行读写和操作。

  1. 一个进程关闭后,操作系统会回收所有占用的内存。
  2. 进程之间内容相互隔离,也就是说一般情况下不能跨应用通信。

单进程浏览器

单进程浏览器,顾名思义,浏览器所有的功能模块都在一个进程里面,这些功能模块包含了网络,插件,JS运行环境等等,这样的架构会造成一些不好的用户体验。

问题1:容易崩溃

单进程浏览器需要借助插件来实现各种功能,但是插件是最容易出现问题的模块,而且还运行在浏览器的进程中,所以一个插件的崩溃会引起整个浏览器的崩溃。

问题2:不流畅

因为所有脚本运行在一个单进程的浏览器页面中,这就意味着同一时刻只能有一个模块可以执行。所以一旦一个脚本无限循环,他会独占整个线程,导致浏览器失去响应,变卡顿。

问题3:不安全

插件可以用C++等代码编写,可以获取到操作系统的任意资源,如果是恶意插件,那么就会遭受攻击。

多进程浏览器

多进程浏览器将插件进程,渲染进程,浏览器主进程都分成单独的模块,然后模块之间通过IPC机制进行通信。

问题1的解决:

由于进程是相互隔离的,所以当一个页面或者插件崩溃时,影响到的仅仅是当前的页面进程或者插件进程,并不会影响到浏览器和其他页面,这就完美地解决了页面或者插件的崩溃会导致整个浏览器崩溃,也就是不稳定的问题。

问题2的解决:

JavaScript 也是运行在渲染进程中的,所以即使 JavaScript 阻塞了渲染进程,影响到的也只是当前的渲染页面,而并不会影响浏览器和其他页面,因为其他页面的脚本是运行在它们自己的渲染进程中的。所以当我们再在 Chrome 中运行上面那个死循环的脚本时,没有响应的仅仅是当前的页面。

问题3的解决:

采用多进程架构的额外好处是可以使用安全沙箱,你可以把沙箱看成是操作系统给进程上了一把锁,沙箱里面的程序可以运行,但是不能在你的硬盘上写入任何数据,也不能在敏感位置读取任何数据,例如你的文档和桌面。Chrome 把插件进程和渲染进程锁在沙箱里面,这样即使在渲染进程或者插件进程里面执行了恶意程序,恶意程序也无法突破沙箱去获取系统权限

为什么仅仅打开了一个页面,却有4个进程

最新的Chrome 浏览器包括以下几个进程

  1. 浏览器主进程
  2. GPU进程
  1. 网络(NetWork)进程
  2. 多个渲染进程
  1. 多个插件进程

浏览器进程 :主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。

渲染进程 :核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。

GPU 进程 :其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。

网络进程 :主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。

插件进程 :主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。

所以打开 1 个页面至少需要 1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程,共 4 个;如果打开的页面有运行插件的话,还需要再加上 1 个插件进程。