{{ v.name }}
{{ v.cls }}类
{{ v.price }} ¥{{ v.price }}
多进程架构(原文地址:http://www.chromium.org/developers/design-documents/multi-process-architecture)
这篇文档描述了chromium的上层架构。
a、问题所在
几乎没可能建立一个永远不崩溃或挂机的渲染引擎,也不可能建立一个完美安全的渲染引擎。
某些方面来说,现在的browser有点像过去的单用户,多任务的操作系统。在那样的操作系统里,如果有一个胡作非为的程序,将会让整个系统崩溃。也就像一个胡作非为的页面、或插件错误,就能带来整个浏览器和当前运行的所有标签的崩溃。
现在的操作系统强壮多了,因为他们将应用程序划分到一个个的独立进程中,这些进程间独立运行,不互相影响,一个程序中的crash一般不会影响到别的应用程序或者整个系统,而且某用户要访问别的用户的数据也是不允许的。
b、架构概览
主进程,也叫做"browser"进程,运行ui和管理tab。
同样的,tab进程叫做"render"进程,使用web-kit排布引擎来解析和排布html。
c、管理多个render进程
每个render进程都有一个全局的renderprocess对象管理和父进程(browser)间的通信以及全局的状态,browser对每个renderprocess都维护了一个对应的renderprocesshost,用来管理browser的状态和用于通信。browser和renderer之间的通讯使用chromium'sipcsystem。
d、管理视图
每个render进程都有一个或者多个的renderview对象,这些对象都由renderprocess管理,renderview对应着每个tab的内容。
对应的renderprocesshost维护着一个renderviewhost对象,这个对象对应着每个renderer里的view。
每个view拥有一个viewid,这个viewid是用来区分一个renderer里的多个不同的view,并且这些id在一个renderer进程中是唯一的,但在整个browser中不是唯一的,所以要区分一个view需要一个renderprocesshost和一个viewid。
从browser到指定的tab内容之间的通信是通过这些renderviewhost对象来完成的,这些renderviewhost对象知道怎么把消息通过renderprocesshost传到renderprocess,然后再传到renderview。
e、组件和接口
在render进程中:
renderprocess处理ipc是通过browser中对应的renderprocesshost,每个render进程都只有一个renderprocess,这就是browser和render的通信路径了。
renderview对象和browser中对应的renderviewhost通信(通过renderprocess),renderview对象也和我们的webkit嵌入层通信。这个对象代表tab或窗口里的页面内容。
在browser进程中:
browser对象代表最高层的浏览器窗口。
renderprocesshost对象代表browser端,browser和renderview的通信,每个render进程只有一个renderprocesshost。
renderviewhost对象包装了和renderview的通信。
browser中的renderwidgethost处理renderwidget的输入和绘画。
f、共享render进程
一般来说,一个新窗口或者一个新tab,就会创建一个新进程,并创建一个renderview,但有时候,可能要多个tab共享一个render进程。
一个web应用打开一个新窗口的时候,他是期待一个同步的通信的,比如javascript的window.open,这个情况下,我们需要在新开的窗口中重用这个进程。
我们也有办法让一个新的tab指向一个已存在的render进程,这种情形是用于进程太多的情况,或者用户已经有一个进程打开导航到域名。这些办法你可以查看这里(http://www.chromium.org/developers/design-documents/process-models)。
g、监测崩溃和胡作非为的renderer
每个ipc连接到browser进程,browser进程都会监测进程的句柄。
如果这些句柄激发,render进程已经崩溃并且tabs被告知这个崩溃。到现在为止,我们会显示一个“sadtab”的页面,通知用户,这个renderer已经崩溃了。点击reload按钮可以让这个页面重新装载,或者打开一个新的导航。当这个发生,我们会通知已经没有进程,并会创建一个新的。
h、让renderer变成一个沙箱
假设webkit运行在一个单独的进程中,我们可以限制它访问系统资源。例如我们可以让这个renderer只是通过他的父进程browser访问网络,同样的,我们可以通过操作系统的权限系统来限制它访问文件系统。
除了限制renderer访问文件系统和网络,我们还可以限制它访问用户的显示和相关的对象。我们每个render进程都运行在一个看不到的窗口里,这个窗口是独立的,叫做“desktop”,这可以阻止一个“危险的”renderer(被植入危险的代码)打开一个新window或者截取你的键盘点击。
i、把内存还回去
正因为renderer运行在一个单独的进程中,所以我们需要考虑隐藏的tabs的低优先级问题。
正常的,windows会把一个最小化的进程自动放进一个“有效的内存池”中,当这个进程处于low-memory状态,windows将把这个内存存放到硬盘中,直到他们变为higher-priority的内存。
为了让用户可见的程序更良好的反应,我们可以把这个原则用于“隐藏”的tabs,当一个renderer不是最高级别的tab时,我们可以释放那个进程的“workingset”大小,作为对系统的暗示,以便系统能把它的内存转放到硬盘上(如果系统认为需要的话)。
因为我们发现,减少workingset的大小,也会降低tab切换的性能。当用户在两个tabs之间切换,我们渐渐的释放内存。这意味着,如果用户切换回最近使用的标签,该标签的内存是更可能被页面化(存到disk)的,而少用的tab反而不会被页面化。
当然,有足够内存的用户不用管这个,因为windows只回收他需要的数据,所以如果内存足够,这样做对性能没有一点的好处。
这有助于我们在低内存的情况下得到更优化的内存占用,少用的tab将会被完全从内存替换到硬盘,而前端的tab,将可以整个装载进来内存中。相比之下,一个单进程的浏览器将其所有的tab数据随机的分发到内存中,这样就没办法把使用或者不实用的数据分离得那么清晰,这样就浪费内存以及性能了。
j、插件
firefox风格的npapi插件会运行在他自己的进程中,和renderer隔开。具体可以看这里:http://www.chromium.org/developers/design-documents/plugin-architecture。