Posted on 2008-10-12 00:30
vlient 阅读(10162)
评论(6) 编辑 收藏 引用 所属分类:
Chrome
问题
构建一个永远不会崩溃或者挂起的排版引擎基本是不可能的,我们同样也不要指望哪天能够构建出一个绝对安全的排版引擎。
我们现阶段的浏览器运行在一个单用户,多合作,多任务的操作系统中。就像一个笨拙的应用程序可以让整个系统崩溃一样。一个糟糕的网页同样可以让一个现代的浏览器崩溃。其原因可能是一个插件出现bug,最终的结果是整个浏览器以及其他正在运行的标签被销毁。
现代操作系统已经非常健壮了,它让应用程序在各自的进程中运行和不会影响到其他程序。一个进程崩溃不会损害到其他进程以及操作系统。同时系统会严格的限制一个用户访问另外一个用户空间的数据。
架构总揽
我们为浏览器的每个标签(Tab)开辟一个独立的进程,这样我们防止整个应用程序因为排版引擎的bug而崩溃。同样我们会严格限制进程访问操作系统及其内存空间。
我们将运行UI和管理标签的插件线程称之为"浏览器进程"或者说是"浏览器",同样,我们将每个标签相关的进程称之为"排版进程"或者说是"排版"。我们使用开源的WebKit作为HTML的解析和排版引擎。
管理排版(Render)进程
每个排版进程都有一个全局的RenderProcess 的对象用以管理和父浏览器进程之间的通讯并且保持全局状态。浏览器每一个排版进程保持一个对应的RenderProcessHost对象用以管理浏览器状态并负责与其他排版进程进行通讯。浏览器进程和排版进程通过Chromium的IPC系统进行通讯。
管理视图(Views)
每个排版进程包含一个或多个RenderView 对象。RenderProcess对象负责管理RenderView 对象以及标签(Tabs)的内容。RenderProcessHost里面包含有RenderViewHost。
同时每个RenderViewHost对应着排版进程的一个视图。在一个排版进程里面的视图都有一个不同的视图ID。这些视图ID有可能和其他排版进程里面的视图ID重名。因此我们确定一个位于的视图需要同时借助RenderProcessHost和视图ID。浏览器通过RenderViewHost 对象与指定标签的内容进行通讯。RenderViewHost 通过RenderProcessHost 传递消息给RenderView上的RenderProcess 对象。
组件和接口
在排版进程内:
在浏览器进程内:
-
Browser 对象负责显示最上层的浏览器窗口。
-
RenderProcessHost 对象显示单个浏览器的侧边 ↔ 排版进程的IPC连接(ps:不太理解这句话,付原文如下:The RenderProcessHost object represents the browser side of a single browser ↔ renderer IPC connection)。每个排版进程仅有一个RenderProcessHost对象。
-
RenderViewHost 对象封装与远程RenderView 之间的通讯。同时负责RenderWidget对象的输入和显示。
更多细节可以参考 How Chromium displays web pages
排版进程的共享
通常情况下。每页新窗口或者是新标签都将在新进程里面打开。浏览器进程负责创建新进程并引导它创建一个RenderView。
有时候有必要让标签或者是窗口共享排版线程。一个网页应用开启了一个新的窗口并采用同步实现进行通讯。例如:Javasript里面的window.open。在这种情况下,当我们创建一个新的窗口或者一个新的标签。我们需要重用当前进程打开的窗口。我们还有一种策略:当创建进程的数量太多的时候,我们会把新创建的标签附加到已有的进程上。或者当用户已经有一个进程打开了所需的地址。这个策略我们已经在in Process Models. 里面描述过。
崩溃检测或异常排版
每个浏览器进程的IPC连接会监视进程的句柄(handle),如果句柄指示异常(are signaled),排版引擎已经崩溃并并通知到标签。然后我们会显示一个"sab tab"页面通知用户排版引擎已经崩溃。这个页面可以通过按刷新键重新加载或者输入一个新的地址进行浏览。当这种情况发生时,我们通知用户原来的进程已经不存在了我们需要创新一个新的进程。
排版引擎的沙盒模型
当我们将WebKit至于一个独立的进程内,就给了我们机会去限制它访问系统资源。例如,我们可以确保排版引擎的对网络的访问都是通过它的父进程完成的。同样,我们可以通过操作系统内置的权限限制排版引擎对文件系统的访问。
除了能够限制排版引擎对文件系统和网络的访问外,我们还可以增加对其对用户的显示和相关对象的限制。我们可以在一个用户不可见的windows 桌面上运行一个排版进程。
这样我们可以防止排版引擎打开新的窗口或者被劫持按键。
返还内存
给定的排版引擎运作在独立的进程内,它会将隐藏的标签当做低优先级处理。通常情况下,被最小化的窗口的进程会讲他们的内存自动返还到"可以内存"池内,在低内存情况下。窗口会将这部分内存交换到高优先级内存。这样可以保证用户可视的程序得到更多相应。我们可以讲这个策略用于隐藏的标签。当一个排版进程没有最上层的标签,我们可以减小这个进程的工作设置大小,这样会提示系统如果有需要可以讲这个进程的内存优先交换出去。因为我们发现减少工作设置大小会降低两个标签间的切换速度,我们采取逐步释放的策略。这意味着如果用户在常用标签间切换的时候,那些不常被使用的标签其内存会优先被置换出去。
用户如果有足够多的内存运行他们所以的程序的时候他们是不会体会到这个差别的。系统仅仅会回收需要的内存,如果你有足够的内存是不会有性能损失的。
这会帮助我们在低内存环境下获取更多优化的内存足迹。那些不常使用且被置于后天的标签其内存可以完全交换给前置的标签。于此形成对比的是,一个单进程浏览器,它所有标签的数据仅仅会随意的散落在内存中,而其不可能将使用过和未使用的内存区分开,既浪费了内存空间有损害了系统性能。
插件
Firefox形式的NPAPI 插件运行在他们自己的进程内,同其他的排版进程保持分离。这些在Plugin Architecture.有进一步的描述。
资源
Multi-threaded user interface in Windows on MSDN.
本文翻译自http://dev.chromium.org/developers/design-documents/multi-process-architecture