『输入URL到渲染完成系列(一)』之浏览器架构

2,134 阅读12分钟

前言

大家好呀,这篇文章的内容主要为浏览器的架构知识,是本系列的第一篇文章。

《包教不包会的输入URL到渲染完成系列》文章的目标有这么几点:

  • 回顾浏览器和网络这两块的知识,通过这一过程,可以建立一个完整的浏览器,网络的知识体系。
  • 与大家分享,共同进步。如果可以让大家有一丢丢的进步,我会开心到飞起来。
  • 希望可以建立一种自上而下的学习方法。

小声BB:

  • 见解有限,如有描述不当之处,还请大家指出,如有错误,会及时修正。(Doge保命)
  • 文章内容存在大量的引用,在本人粗浅理解下整理了其中的内容,引用的链接放置在子标题下方,如有需要,可以进入原文深入了解。如有侵权,给我留言,立马删。

大纲

  1. 浏览器和浏览器内核的前世今生
  2. 进程与线程
  3. 浏览器架构的演变
    1. 单进程架构
    2. 多进程架构
    3. 面向服务的架构
  4. 多进程架构简介
  5. 进程模式
  6. 浏览器内核的组成
  7. 拓展资料

浏览器和浏览器核心的前世今生

引自:浏览器野史 UserAgent列传历史在重演:从KHTML到WebKit,再到Blink

这一部分,我们简单的列一下浏览器和浏览器核心的发展历史

浏览器

  • 1990年: Nexus(WorldWideWeb)诞生
  • 1993年1月23日:Mosaic诞生
  • 1994年12月:Netscape(Mozilla)诞生
  • 1995年4月:Opera诞生
  • 1995年8月16日:Internet Explorer诞生
  • 2002年9月23日:Firefox诞生
  • 2003年1月7日:Safari诞生
  • 2008年9月2日:Chrome诞生

如果对这一部分感兴趣,可以去浏览器野史 UserAgent列传了解一下。

浏览器内核

浏览器内核主要包括以下三个技术分支:排版渲染引擎、 JavaScript引擎,以及其他。

  • 1997年 Trident
  • 1998年 KHTML和KJS
  • 2000年 Gecko
  • 2001年 WebKit
  • 2003年 Presto
  • 2010年 混合引擎(双核)
  • 2013年 Blink
  • 2015年 EdgeHTML

在浏览器内核的发展中,发生了一些有趣的事情,具体可以查看_历史在重演:从KHTML到WebKit,再到Blink

小结

这一部分历史其实不用记住,需要了解的点就是KHTML——>Webkit——>Blink由于多方的理念差异,导致的浏览器内核的不断进步。

进程与线程

引自: What’s the Diff: Programs, Processes, and Threads 维基百科进程 维基百科线程

进程

进程(process),是指计算机中已运行的程序。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。

线程

线程(thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。

两者之间的区别和联系

用户下达运行程序的命令后,就会产生进程。进程需要一些资源才能完成工作,且为依序逐一进行,也就是每个CPU核心任何时间内仅能运行一项进程,不同的进程之间是相互隔离的

而进程中的每个线程共享该内存和资源。在单线程进程中,进程包含一个线程。进程和线程是相同的。

在多线程进程中,该进程包含多个线程,以允许同时有多位用户运行同一程序,却不会相冲突。每个线程将拥有自己的栈,但是进程中的所有线程将共享堆。也就是说同一进程中的不同线程,是可以并行的。

小结

  • 了解进程和线程的概念
  • 进程之间的内容相互隔离,一个进程中可以有多个线程,同一进程里面的线程是可以并行的

想要详细了解程序,进程和线程的不同点,可以阅读What’s the Diff: Programs, Processes, and Threads

浏览器架构的演变

单进程内容引自:浏览器工作原理与实践 多进程和服务化内容引自:

以前:单进程架构

单进程浏览器是指浏览器的所有功能模块都是运行在同一个进程里,这些模块包含了网络、插件、JavaScript 运行环境、渲染引擎和页面等。单进程浏览器的架构如下图所示:

如此多的功能模块运行在一个进程里,是导致单进程浏览器不稳定不流畅不安全的一个主要因素。

问题 1:不稳定 早期浏览器需要借助于插件**来实现诸如 Web 视频、Web 游戏等各种强大的功能,但是插件是最容易出问题的模块,并且还运行在浏览器进程之中,所以一个插件的意外崩溃会引起整个浏览器的崩溃。

除了插件之外,渲染引擎模块也是不稳定的,通常一些复杂的 JavaScript 代码就有可能引起渲染引擎模块的崩溃。和插件一样,渲染引擎的崩溃也会导致整个浏览器的崩溃。

问题 2:不流畅 所有页面的渲染模块、JavaScript 执行环境以及插件都是运行在同一个线程中的,这就意味着同一时刻只能有一个模块可以执行。

除了上述脚本或者插件会让单进程浏览器变卡顿外,页面的内存泄漏也是单进程变慢的一个重要原因。通常浏览器的内核都是非常复杂的,运行一个复杂点的页面再关闭页面,会存在内存不能完全回收的情况,这样导致的问题是使用时间越长,内存占用越高,浏览器会变得越慢。

问题 3:不安全

这里依然可以从插件和页面脚本两个方面来解释该原因。

插件可以使用 C/C++ 等代码编写,通过插件可以获取到操作系统的任意资源,当你在页面运行一个插件时也就意味着这个插件能完全操作你的电脑。如果是个恶意插件,那么它就可以释放病毒、窃取你的账号密码,引发安全性问题。

至于页面脚本,它可以通过浏览器的漏洞来获取系统权限,这些脚本获取系统权限之后也可以对你的电脑做一些恶意的事情,同样也会引发安全问题。

现在:多进程架构

现代的多线程架构更加稳定,因为它们将应用程序置于相互隔离的单独进程中。一个应用程序中的崩溃通常不会损害其他应用程序或浏览器的完整性,并且每个用户对其他用户数据的访问受到限制。

对浏览器选项卡使用单独的进程,以保护整个应用程序免受渲染引擎中的错误和干扰。Chrome还限制了每个渲染引擎进程对其他进程以及系统其余部分的访问。在某些方面,这个为Web浏览器带来了内存保护和访问控制的好处。

未来:面向服务的架构

Chrome的服务化示意图,将不同的服务移至多个进程和一个浏览器进程。

由于多进程架构会造成占用更多的资源以及更加复杂的体系架构,所以Chrome 正在进行体系架构改变,将浏览器程序的每个部分,作为一项服务运行,从而可以轻松拆分为不同的进程或汇总为同一个进程。(仔细观察上图不同进程合并到浏览器进程的过程)

具体的想法如下:

  • 当 Chrome 在强大的硬件上运行时,它可能会将每个服务拆分为不同的进程,从而提供更高的稳定性。
  • 但如果它位于资源约束的设备上,Chrome 会将服务整合到一个进程中,从而节省内存占用。

这个进程模型的方案会在多进程架构详解中的进程模型部分进行更加详细的介绍。

多进程架构简介

此部分参考了以下内容:

不同进程

  • 浏览器(Browser):主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
  • 渲染器(Renderer):控制选项卡内,网站里显示的所有内容。
  • 插件(Plugin):控制网站使用的插件,例如:Flash。
  • GPU:独立于其他进程,专用于处理 GPU 任务。

还有更多的流程,如:扩展进程(Extension Process)和实用进程(Utility Process)。如果你想查看 Chrome 中正在运行的进程数,请点击右上角的选项,菜单图标→选择更多工具→任务管理器

这将打开一个窗口,其中包含当前正在运行的进程列表以及它们使用的 CPU/内存信息。

小结

通过这一部分,我们已经了解了浏览器里面有什么进程,以及各个浏览器进程的作用。

进程模式

详细内容可以看: process-models 引自:浏览器多进程架构

site和site-instance

首先,我们先介绍一下site和****site-instance的概念。

  • site 指的是相同的 registered domain name (例子, google.com ) 和 协议 (例子., https://) 。比如 z.baidu.comb.baidu.com 就可以理解为同一个 site(注意这里要和 Same-origin policy 区分开来,同源策略还涉及到子域名和端口)
  • site-instance指的是一个网站实例是一些相同网站的相连网页的集合。我们这样认为两个页面是相连的:如果他们可以在脚本代码中获取彼此的引用的话。满足下面两中情况并且打开的新页面和旧页面属于上面定义的同一个 site,就属于同一个site-instance
  1. 用户通过 这种方式点击打开的新页面
    • JavaScript code 打开的新页面(比如 window.open)

四种进程模式

Chromium 提供了四种进程模式,他们影响了浏览器分配页面给渲染进程的行为,比如采用某个模式况会给 tab 分配新进程,而采用另外一个模式则不会,下面是四种模式的介绍,Chrome 默认采用第一个模式。

  • Process-per-site-instance(default)
    • 同一个 site-instance 使用一个进程
  • Process-per-site
    • 同一个 site 使用一个进程
  • Process-per-tab
    • 每个 tab 使用一个进程
  • Single process
    • 所有 tab 共用一个进程

为什么使用 Process-per-site-instance 这种进程模式

因为这种模型兼顾了性能与易用性,是一个比较中庸通用的模式

  • 相较于 Process-per-tab,能够少开很多进程,就意味着更少的内存占用
  • 相较于 Process-per-site,能够更好的隔离相同域名下毫无关联的 tab,更加安全

浏览器内核的组成

引自:

浏览器内核主要包括以下三个技术分支:排版引擎、 JavaScript引擎,以及其他。 接下来我们可以看下浏览器内核中到底有些什么。 图:WebKit架构 图:WebKit2接口和进程模型 图:Blink架构 浏览器的渲染进程是多线程的,那进程里面的线程都是什么呢?

  1. GUI渲染线程
    • 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
  2. JS引擎线程
    • 也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
    • JS引擎线程负责解析Javascript脚本,运行代码。
  3. 事件触发线程
    • 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
  4. 定时触发器线程
    • 传说中的setIntervalsetTimeout所在线程
  5. 异步http请求线程
    • 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求

图:浏览器内核线程

拓展资料

由于Chrominu的项目很大,如果要通读的话可能会陷入某些细节中出不来。这里建议在有需要的情况下去阅读。这里的难度不是因为这个文档难理解,主要是因为项目很大,资料很多,人很茫然。

总结

作为这一系列的第一篇,从浏览器历史开始,介绍了浏览器架构演变,浏览器中不同进程的作用以及进程模式。

看完之后如果对浏览器架构有了初步的认识,知道浏览器有几种进程,以及它们分别有什么作用,就达到了本文的目的了。如果想要有更加深入的了解,可以看『包教不包会的输入URL到渲染完成系列(一)』之浏览器架构-详细版

如果觉得还不错的话,可以点赞,加收藏,来关注这一系列文章的输出。欢迎大家监督(催更)。

再次感谢

也许写的不大好,不过开始了,就走下去。还是那句话

不怕真理无穷,进一寸有一寸的欢喜