# 前言
打开一个Tab页,查看Chrome任务管理器:
# 进程和线程
进程:是一个程序的运行实例(操作系统的层面)。每当启动一个程序,操作系统为该程序分配一块内存,用于存放代码、运行时数据、一个执行任务的主线程。
线程:线程是由进程进行管理,负责处理任务,进程中使用多线程可以实现并行处理提高效率。
关键点:
- 线程依附于进程,进程中使用多线程提高运算效率。
- 多线程之间是可以共享进程中的数据。
- 进程中任意某个线程执行出错,会导致整个进程崩溃。
- 进程之间互相隔离。进程只能访问各自的数据,避免了进程之间互相影响,这样就避免了如果一个进程崩溃,不会影响其他进程。
- 进程(浏览器程序)关闭后,操作系统会回收该进程的内存。
# 单进程浏览器
浏览器所有功能模块都运行在一个进程中,包含页面线程、网络线程等等。
# 缺陷
- 不稳定
一旦某插件崩溃,会导致整个浏览器崩溃;一些复杂的JavaScript代码有可能引起渲染引擎模块的崩溃,导致整个浏览器的崩溃。 - 不流畅
页面渲染模块、JavaScript模块、插件模块都是运行在同一个线程中的,意味着同一时刻只能有一个模块可执行。比如JavaScript脚本里有死循环,当执行的时候会独占整个线程,其他运行在该线程的模块无法执行,这样会导致浏览器整个失去响应,卡顿。JavaScript或者插件是有可能内存泄漏,导致整个浏览器进程变卡顿。 - 不安全
插件可以使用C/C++等编写,通过插件可以获取到操作系统的任意资源,打开一个页面运行插件时也意味着这个插件能操作整个电脑。页面脚本,可以通过浏览器的漏洞来获取系统权限。
# 多进程浏览器
# 初期架构
- 每个页面各自运行在单独的渲染进程、插件运行在单独的插件进程。
由于进程之间相互隔离,当一个页面或者插件崩溃,影响的仅仅是当前的页面进程或插件进程,并不会影响到浏览器和其他页面。同样的,JavaScript运行在渲染进程中的,即使JavaScript阻塞了渲染进程,影响到的也只是当前的渲染页面,不会影响浏览器和其他页面,因为其他页面是运行在各自的渲染进程中。 - 进程之间IPC机制通信。
- 使用沙箱去使用多进程,跟操作系统隔离开,确保系统安全。
# 当前架构
Chrome浏览器包括:浏览器主进程、GPU进程、网络进程、多个渲染进程、多个插件进程。
- 浏览器进程 => 负责界面显示、用户交互、子进程管理、数据存储等等。
- GPU进程 => 初期Chrome并没有GPU进程,GPU的使用初衷是为了实现3D CSS的效果,后来Chrome的网页UI界面选择采用GPU来绘制,让GPU成为浏览器普遍的需求。最终,Chrome在架构上也引入了GPU进程。
- 网络进程 => 负责页面的网络资源加载。
- 渲染进程 => 负责解析HTML、CSS、JS生成可交互的网页,排版引擎Blink、JavaScript引擎V8都是运行在该进程中。默认情况下,Chrome会为每个Tab标签创建一个渲染进程。渲染进程都是运行在沙箱中。
- 插件进程 => 负责插件的运行,插件进程确保了插件崩溃不会导致整个浏览器页面崩溃。
带来的一些问题:
- 更高的资源占用 => 每个进程都会包含公共基础模块的副本(如JavaScript运行环境),这样浏览器会消耗更多的内存资源。
没事,可劲儿吃内存,想起当初我的16G外星人👽Chrome吃了我8个多G - 更复杂的体系架构 => 浏览器各模块之间耦合性高、扩展性差。
# 面向服务架构(SOA)
Services Oriented Architecture。
各个模块重构为独立的服务(Service),每个服务都能在独立的进程运行。访问服务需要使用定义好的接口,通过IPC通信,这样就能构建一个更内聚、松耦合、易于维护和扩展的系统。有一种类似于微服务的概念
Chrome把UI、数据库、文件、设备、网络等无关痛痒的模块拆出来作为基础服务提供(Chrome Foundation Service)。
弹性架构:
- 设备内存多:渲染进程 + 插件进程 + 浏览器主进程 + 基础服务各自用各自的进程。
- 设备内存少:渲染进程 + 插件进程 + 浏览器主进程(基础服务都放到主进程中)。
# 总结
- 早期设备内存普遍小,一般都是单进程多线程架构,弊端容易程序崩溃。
- 后来设备内存大,一般多进程架构,弊端占内存。