1、 设计动机 2006年前后的浏览器更多的是采用单进程架构。这样做有很多好处,例如
实现/部署简单快速 内存占用少 通信高效,比 IPC/socket 等通信方式简单便捷 但是与此同时,单进程架构有一个巨大的痛点:任何内部模块的崩溃「Crash」都会导致整个进程崩溃。因此,在单进程模式之下,其中一个页面/插件发生了错误,整个浏览器和所有当前运行的页面都无法正常运行。这也是早期的计算机容易崩溃的原因之一。
而我们几乎不可能构建一个永远不会崩溃或挂起的渲染引擎。
随着内存条变得越来越便宜,健壮性成为了现代浏览器的追求目标。Chromium 的多进程架构将应用程序「网页」放在彼此隔离开的单独进程中。一个应用程序的崩溃不会损害其他程序和整个浏览器的完整性。
2、渲染进程 在 Chromium 多进程架构中,有一个主进程用于运行 UI 并且管理其他进程,称之为 Browser process 或者 Browser.
大多数情况下,浏览器的渲染进程是由 Browser process 启动。当用户在浏览器中打开一个新的页面时,Browser 会启动一个新的渲染进程。通俗来说,一个网页就是一个渲染进程:renderer process
每一个渲染进程,都运行在一个独立的隔离沙箱环境中,浏览器限制了网页进程对系统资源的直接访问,例如,我们不能直接通过 JavaScript 在网页中读写本地文件。这样做带来的好处就是,即使一个网页崩溃,也不会影响其他网页的正常运行。
INFO 坏处就是造成了更多的内存损耗,因此,多进程架构需要花费更巧妙的方案来解决内存的消耗问题。
渲染进程通过 IPC/Mojo(进程间通信)与浏览器进程(Browser Process)交互,例如请求资源或通知用户操作。
renderer process 内部包含多个线程和模块,协同完成渲染任务:
主线程(Main Thread):负责解析 HTML、CSS,构建 DOM 和 CSSOM。执行 JavaScript 代码。处理用户交互事件(如点击、输入)。
合成线程(Compositor Thread):负责将页面内容分层(Layer),并合成最终的图像。处理滚动、动画等高性能操作。
光栅化线程(Raster Thread):将渲染树中的内容转换为位图(Bitmap),以便显示在屏幕上。
Web Worker 线程:如果网页使用了 Web Worker,渲染进程会创建额外的线程来执行 JavaScript 代码,避免阻塞主线程。
3、内存优化策略 多进程的设计思路,虽然通过隔离沙箱的方式提高了浏览器的稳定性,但是也带来了一些内存的消耗问题。因此,我们在了解多进程架构时,需要对浏览器在此基础之上所做的内存优化策略有一定的了解。
主要有如下三个策略:
3.1、共享 renderer process 通常情况下,一个新的窗口/选项卡会在一个新的进程中打开。主进程会创建一个新的进程,并指示它创建一个RenderFrame,这可能在页面中创建更多的 iframe.
但是有的时候希望能够在 窗口/tab 之间共享 render process
例如我们在网页中使用 window.open 打开一个新页面,如果新的页面属于同一来源,那么这两个页面就会共享进程
除此之外,如果用户在使用浏览器时,同时打开了过多的 tab,此时如果每个页面都享有独立的进程的话,那么内存的消耗就会变得非常巨大。因此 chromium 此时会有针对性的同源共享策略来应对这种情况
3.2 Giving back memory Giving back memory 是一种重要的内存优化策略。
在 windows 操作系统中,最小化到后台的进程会自动将内存放入一个「可用内存池」中,在内存不足时,windows 会在换出优先级较高的内存之前,将此内存交换到磁盘。也就是说,windows 会利用磁盘的存储空间让内存的使用压力变小
这样的策略同样可以运用于浏览器中。
当一个 renderer 隐藏到后台时,我们可以释放该进程的 work set 大小,以提示系统在必要时首先将该内存交换到磁盘。
因为我们发现,当用户在两个 tab 之间进行切换时,如果马上就减小 work set 的大小会降低 tab 的切换性能,因此先标记并在必要时候释放内存是一个更好的选择
所以,如果你的电脑内存足够大不需要考虑这个问题,系统只会在内存不够时运用这个空间交换策略,这有助于我们在低内存的情况下获得更优的内存使用。
内存不足时,低频使用的 tab 页可以完全置换为磁盘空间,当前处于前台的 tab 可以完全加载到内存中以获得最佳的运行速度。
而单进程架构则无法使用这种内存优化策略。单进程浏览器会将所有 tab 的数据随机分配在内存中,无法干净的区分使用的和未使用的数据,这对于内存和性能而言都是一种浪费
这种优化策略又称为虚拟内存,在使用时的表现就是,如果你重新点开长时间没有使用、你又没有关闭的 tab 页时,页面会首先白屏一段时间,然后才会显示出来。
3.3 渲染进程共享基础服务进程 为了不重复创建基础服务模块,浏览器会把一些基础服务单独提炼出来,作为一个独立的进程来运行。所有的渲染进程只需要负责与基础服务进程进行 IPC 通信即可。
例如,当我们在网页中要发起一个请求时,此时,渲染进程会通过 IPC 与 Browser 通信,Browser 会创建一个新的网络进程,然后将请求转发给网络进程。网络进程会发起请求,然后将响应返回给渲染进程。
我们可以在设置中的 更多工具 -> 任务管理器 中看到单独的 Network Service 进程。
常见的基础服务进程有
GPU 进程 Network Service Storage Service Audio Service Video Service ... 除了单独将较重的模块单独运行在独立的进程中之外,Browser 进程也会承担一些相对较轻的其他公共逻辑。例如:监听用户的输入事件并管理、分发。
最后需要注意的是,定时器线程运行在单独的 Renderer 进程中,专门用来管理单个 Renderer 进程的定时器任务的调度与执行。
4、总结 了解浏览器多进程架构,是深入理解浏览器事件循环体系的基础前提。大家一定要认真掌握。
Loading comments...