博客文章,请直接访问https://dulinrain88.github.io/
本文讲述的是Chromium渲染器进程所支持的几种不同的进程模型以及各模型存在的问题。
Web内容已演变为包含大量在浏览器中运行的动态代码,从而使许多网站更像是应用程序而不是纯文档。这种演变也将浏览器的角色从一个简单的文档渲染器转换成了一个操作系统。Chromium就是按照类似操作系统的样子去开发的,通过使用多个操作系统进程来确保站点-站点的隔离以及站点-浏览器的隔离,从而让这些应用以安全和健壮的方式运行。这改善了浏览器的健壮性,因为每个进程运行在独立的地址空间,由操作系统进行调度,并且一个挂了也不会影响另外一个。用户也可以在Chrome的任务管理器中看到每个进程的资源使用。
有很多种方式可以将web浏览器划分到不同的操作系统运行,而选择最好的架构则取决于很多种因素,其中包括:稳定性、资源使用率以及对实际使用的监测。Chromium支持四种不同的进程模型可供实验,并且将其中一种适合大多数用户的模型作为默认模型。
Chromium支持四种不同的模型,不同的模型会影响浏览器如何将页面分配给渲染器进程。默认情况下,Chromium为用户访问的每个站点实例(Process-per-site-instance, 即each instance of a web site)分配一个独立的进程。然而,用户也可以通过命令行在Chromium启动时选择其它的模型:每个站点所有实例公用一个进程(one process for all instances of a web site)、每一组连接的tab公用一个进程(one process for each group of connected tabs)、只有一个进程(everything in a single process)。这些模型的区别在于其是否反映了内容的来源、tab之间的关系或者2者共有。本节将详细讲解这几种模型,稍后会在文档中讲述当前实现的各种注意点。
默认情况下,Chromium会为用户访问的站点的每个实例创建一个渲染器进程。这样可以确保不同的站点渲染在独立的进程中,并且对同一站点的独立访问也是相互隔离的。因此单个站点实例的失败(例如:渲染进程崩掉)或者大量资源使用不会影响浏览器的其它部分。这种模型既基于页面内容的来源,也基于可能由脚本关联的不同tab。因此,2个tab的页面可能是通过同一个进程渲染的,当导航到一个跨站的页面时可能会切换到一个新的渲染器进程。
请注意,Chromium当前的实现中有一些重要警告,请参见下面的“警告”部分。
具体而言,这里定义的站点(site)是域名(如google.com或者bbc.co.uk)+ 协议(如https://)。这个和同源策略(Same Origin Policy)中的源(Origin)定义很像,但是它会将子域名(如mail.google.com和docs.google.com)以及端口(如 http://foo.com:8080)都视为同一个站点(site)。 一个“站点实例(site instance)”是相互连接的相同站点的集合。这里“连接”的意思是其中页面之间可以通过脚本获得对应页面的引用(如:某个页面使用Javascript在另一个窗口打开一个新的页面)。
问题:a标签算吗?location.href算吗
Chromium也支持将不同站点互相隔离的模型,但是会将所有相同站点的实例放入一个渲染进程处理。要想使用这种模型,可以在Chromium启动时传递–process-per-site命令。这种模型会创建较少的渲染器进程,以牺牲一些健壮性为代价来降低内存开销。这种模型只会基于内容的源,不会基于不同tab之间的关系。
process-per-site-instance 和 process-per-site 模型在创建进程时都会考虑内容的来源。Chromium也支持一种简单的模型,这种模型将一组script连接的tab放到一个渲染进程处理。这种模型可以在启动时通过--process-per-tab命令行启用。
具体来说,我们将一组具有脚本连接彼此的tab称为浏览实例,这也对应于HTML5规范中的“相关浏览上下文单元”。该集包含一个tab和使用Javascript代码打开的其他所有tab。这种tab必须在相同的进程中呈现,以允许在它们之间(最常见的是在同一来源的页面之间)进行Javascript调用。
值得注意的是,在process-per-tab模型中,Chromium仍然会在觉得必要或者为了安全的情况下强制进程交换。例如,普通页面不允许和类似“设置”或者“新标签页”等特权页面共享进程。结果就是,该模型在实践中并没有比Process-per-site-instance简单得多。
为了对比,Chrome也支持通过--single-process开启单进程模型。在这种模型里,浏览器和渲染引擎都在一个操作系统进程中运行。
单进程模型为测量多进程模型架构在不同负载下的性能提供了基准。它并不一种安全或健壮的架构,因为任何一个渲染器挂掉都会导致整个浏览器进程挂掉。它旨在用于测试和开发目的,并且可能包含其他架构中不存在的错误。
在每一种多进程架构模型中,Chromium的渲染器进程都在一个沙箱进程中执行,这个沙箱进程对用户计算机只有有限的访问能力。这些进程没法直接访问用户的文件系统、显示器以及大多数其它资源。它们智能通过浏览器进程对部分资源进行有限的访问,这样可以在这个地方施加安全策略。这样的结果就是,Chromium的浏览器进程可以减轻被利用的渲染引擎可能造成的损害。 浏览器插件,如Flash和Silverlight,也是在它们各自的进程中运行,有些像Flash之类的插件也是在Chromium的沙盒中执行的。在Chromium支持的每一种多进程架构中,每一类激活的插件都运行在同一个进程实例中。因此,所有的Flash插件都运行在相同的进程中,不论它出现在哪个站点或tab。
这一小节将列出Chromium多进程模型的当前实现中的一些警告以及对应的说明:
大多数渲染器在tab内发起的导航不会导致进程的交换。如果用户点击一个链接,提交一个表单或者被js重定向,如果目标是跨站的话,Chromium不会试图切换渲染进程。Chromium只会在由浏览器发起的跨站导航情况下切换渲染进程,比如在地址栏输入一个URL或者点击一个书签。结果就是,来自不同站点的页面可能会运行在相同的进程中,这个在process-per-site-instance和process-per-site这2种模型中都有可能。这个情况可能会在Chromium未来版本作为站点隔离的一部分做出改变。
然而,页面也可以使用一种机制建议浏览器让link打开的页面在一个不同的线程中渲染。方法就是给link加上rel=noreferrer 和 target=_blank属性,大概率情况下是可以生效的。
子frame当前是和其父页面渲染在同一个进程。经过跨站子frame(如iframe)没有对父页面脚本的访问并且可以安全地放到一个独立的进程中执行,但是Chromium还没有这么做。和前面一点类似,这意味着不同站点的页面可能还是会运行在同一个进程。这可能会在未来的版本中改变。
Chromium创建的进程数量是有限制的。这可以避免浏览器占用过多的用户计算机资源。这个限制是根据计算机的内存按比例来的,最多会有80个进程。因为有这么一个限制,所以可能会出现一个进程为多个站点服务。这种复用是随机的,但是未来的Chromium可能会采用启发式的算法让更加智能的将站点分配给渲染器进程。
Chromium中有2个类来表示各种模型所需要的抽象:BrowsingInstance 和 SiteInstance。
BrowsingInstance类表示浏览器中的一组脚本连接的tab,在HTML 5规范中也称为相关的浏览上下文的单元。 在“process-per-tab”模型中,我们为每个BrowsingInstance创建一个渲染器进程。
SiteInstance类表示同一站点中的一组连接页面。 它是BrowsingInstance中页面的细分,并且重要的是BrowsingInstance中每个站点只有一个SiteInstance。 在process-per-site-instance进程模型中,我们为每个SiteInstance创建一个渲染器进程。而在实现process-per-site模型时,我们保证所有的相同站点的所有SiteInstance都最终在同一个进程中。