`

Chrome的进程间通信(三)

阅读更多

Chrome的进程间通信(三)

1. 基本的进程结构

Chrome是一个多进程的架构,不过所有的进程都会由老大,Browser进程来管理,走的是集中化管理的路子。在Browser进程中,有xxxProcessHost,每一个host,都对应着一个Process,比如RenderProcessHost对应着RenderProcess,PluginProcessHost对应着PluginProcess,有多少个host的实例,就有多少个进程在运行。。。

这是一个比较典型的代理模式,Browser对Host的操作,都会被Host封装成IPC消息,传递给对应的Process来处理,对于大部分上层的类,也就隔离了多进程细节。。。

2. Render进程

先不扯Plugin的进程,只考虑Render进程。前面说了,一个Process一个tab,只是广告用语,实际上,每一个web页面内容(包括在tab中的和在弹出窗口中的...),在Chrome中,用RenderView表示一个web页面,每一个RenderView可以寄宿在任一一个RenderProcess中,它只是依托RenderProcess帮助它进行通信。每一个RenderProcess进程都可以有1到N个RenderView实例。。。

Chrome支持不同的进程模型,可以一个tab一个进程,一个site instance一个进程等等。但基本模式都是一致的,当需要创建一个新的RenderView的时候,Chrome会尝试进行选择或者是创建进程。比如,在one site one process的模式下,如果存在此site,就会选择一个已有的RenderProcessHost,让它管理这个新的RenderView,否则,会创建一个RenderProcessHost(同时也就创建了一个Process),把RenderView交给它。。。

在默认的one site instance one process的模式中,Chrome会为每个新的site instance创建一个进程(从一个页面链开来的页面,属于同一个site instance),但,Render进程总数是有个上限的。这个上限,根据内存大小的不同而异,比如,在我的机器上(2G内存),最多可以容纳20个Render进程,当达到这个上限后,你再开新的网站,Chrome会随机为你选择一个已有的进程,把这个网站对应的RenderView给扔进去。。。

每一次你新输入一个站点信息,在默认模式下,都必然导致一个进程的诞生,很可能,伴随着另一个进程的死亡(如果这个进程没有其他承载的RenderView的话,他就自然死亡了,RenderView的个数,就相当于这个进程的引用计数...)。比如,你打开一个新标签页的时候,系统为你创造了一个进程来承载这个新标签页,你输入www.baidu.com,于是新标签页进程死亡,承载www.baidu.com的进程诞生。你用baidu搜索了一下,毫无疑问,你基本对它的搜索结果很失望,于是你重新输入www.google.com,老的承载baidu的进程死亡,承载google的进程被构建出来。这时候你想回退到之前baidu的搜索结果,乐呵乐呵的话,一个新的承载baidu的进程被创造,之前Google的进程死亡。同样,你再次点击前进,又来到Google搜索结果的时候,一个新的进程有取代老的进程出现了。。。

以上现象,你都可以自己来检验,通过观察about:memory页面的信息,你可以了解整个过程(记得每做一步,需要刷新一下about:memory页面)。我唧唧歪歪说了半天,其实想表达的是,Chrome并没有像我YY的一样做啥进程池之类的特殊机制,而是简单的履行有就创建、没有就销毁的策略。我并不知道有没有啥很有效的多进程模型,这方面一点都没玩过,猜测Chrome之所以采取这样的策略,是经过琢磨的,觉得进程生死的代价可以承受,比较可行。。。

3. 进程开销控制算法

说开销无外乎两方面的内容,一为时间,二则空间。Chrome没有在进程创建和销毁上做功夫,但是当进程运行起来后,还是做了一些工作的。。。
节约工作首先从CPU耗时上做起,优先级越高的进程中的线程,越容易被调度,从而耗费CPU时间,于是,当一个页面不再直接面对用户的时候,Chrome会将它的进程优先级切到Below Normal的级别,反之,则切回Normal级别。通过这个步骤,小节约了一把时间。。。

进程的优先级
在windows中,进程是有优先级的,当然,这个优先级不是真实的调度优先级,而是该进程中,线程优先级计算的基准。在《Windows via C/C++》(也就是《windows核心编程》的第五版)中,有一张详细的表,表述了线程优先级和进程优先级的具体对应关系,感觉设计的很不错,我就不罚抄了,有兴趣的自行动手翻书。。。

当然这只是一道开胃小菜,满汉全席是控制进程的工作集大小,以达到降低进程实际内存消耗的目的(Chrome为了体现它对内存的节约,用了“更为精确”的内存消耗计算方法...)。提到这一点,Chrome颇为自豪,在文档中,顺着道把单进程的模式鄙视了一下,基本意思是:在多进程的模式下,各个页面实际占用的内存数量,更容易被控制,而在单进程的模式下,几乎是不能作出控制的,所以,很多时候,多进程模式耗费的内存,是会小于多线程模式的。这个说法靠不靠谱,大家心里都有谱,就不多说了。。。

具体说来,Chrome对进程工作集的控制算法还是比较简单的。首先,在进程启动的时候,需要指明进程工作的内存环境,是高内存,低内存,还是中等内存,默认模式下,是中等内存(我以为Chrome会动态计算的,没想到竟然是启动时指定...)。在高内存模式,不存在对工作集的调整,使劲用就完事了;在低内存的模式下,调整也很简单,一旦一个进程不再有页面面对观众了,尝试释放其所有工作集。相比来说,中等模式下,算法相对复杂一些,当一个进程从直接面对观众,沦落到切换到后台的悲惨命运,其工作集会缩减,算法为: TargetWorkingSetSize = (LastWorkingSet/2 + CurrentWorkingSet) /2;其中,TargetWorkingSetSize指的是预期降到的工作集大小,CurrentWorkingSet指的是进程当前的工作集(在Chrome中,工作集的大小,包含私有的和可共享的两部分内存,而不包含已经共享了的内存空间...),LastWorkingSet,等于上一次的CurrentWorkingSet除以DampingFactor,默认的DampingFactor为2。而反之,当一个进程从幕后走向台前,它的工作集会被放大为 LastWorkingSet * DampingFactor * 2,了解过LastWorkingSet的含义,你已经知道,这就是将工作集放大两倍的另类版写法。。。

Chrome的Render进程工作集调整,除了发生在tab切换(或新页面建立)的时候,还会发生在整个Chrome的idle事件触发后。Chrome有个计时器,统计Chrome空闲的时长,当时长超过30s后(此工作会反复进行...),Chrome会做一系列工作,其中就包括,调整进程的工作集。被调整的进程,不仅仅是Render进程,还包括Plugin进程和Browser进程,换句话描述,就是所有Chrome进程。。。
这个算法导致一个很悲凉的状况,当你去蹲了个厕所回到电脑前,切换了一个Chrome页面,你发现页面一片惨白,一阵硬盘的骚动过后,好不容易恢复了原貌。如果再切,相同的事情又会发生,孜孜不倦,直到你切过每一个进程。这个惨案发生的主要原因,就是由于所有Chrome进程的工作集都被释放了,页面的重载和Render需要不少的一坨时间,这就大大影响了用户感受,毕竟,总看到惨白的画面,容易产生不好的情绪。强烈感觉这个不算一个很出色的策略,应该有一个工作集切换的底限,或者是在Chrome从idle中被激活的时候,偷偷摸摸的统一扩大工作集,发几个事件刺激一下,把该加载的东西加载起来。。。

整体感觉,Chrome对进程开销的控制,并不像想象中的有非常精妙绝伦的策略在里面,通过工作集这总手段并不算华丽,而且,如果想很好的工作的话,有一个非常非常重要的前提,就是被切换的页面,很少再被继续浏览。个人觉得这个假设并不是十分可靠,这就使得在某些情况下,产生非常不好的用户体验,也许Chrome需要进一步在这个地方琢磨点方法的。。。

分享到:
评论

相关推荐

    CEF:进程间通信 Demo(VS2013)

    4. 为了实现进程间通信,你需要理解CEF的架构,它通常包含三个进程:浏览器进程(负责渲染网页)、主机进程(负责处理用户交互和控制浏览器进程)以及渲染进程(处理HTML内容的呈现)。 5. 在源代码中,查找涉及IPC...

    C#多进程浏览器-仿Chrome浏览器

    为了实现进程间的通信,可能需要用到命名管道、内存映射文件或者.NET的Remoting技术。 此外,为了模拟Chrome浏览器的功能,还需要实现以下关键技术点: 1. **渲染引擎**:负责解析HTML、CSS和JavaScript,生成渲染...

    剥析chrome源码

    ### 剥析Chrome源码:深入理解Chrome的进程间通信机制 #### 一、引言 在现代浏览器设计中,Chrome以其独特的架构和技术脱颖而出,成为业界标杆。Chrome的源码不仅庞大而且复杂,其中涉及的技术细节对于软件开发...

    Chrome源码剖析

    在探索 Chrome 源码时,需要了解它的多进程模型、线程模型、进程间通信机制、插件模型、整体框架设计、跨平台 UI 控件系统、V8 引擎等技术要点。 Chrome 的多进程模型是它的一大特色,包括一个主进程(Browser ...

    google Chrome源码剖析

    这种设计也带来了进程间通信(IPC)的挑战。Chrome 使用 IPC 实现进程间的协作,如数据传输和命令控制。同时,多进程架构增加了内存开销,但可以通过智能的进程管理和资源调度来优化性能。 2. **扩展能力和插件模型...

    chrome核心部分源码

    在源码中,你可以找到关于进程间通信(IPC)和沙盒环境的实现。 5. **网络堆栈**:Chrome的网络堆栈负责处理HTTP/HTTPS请求和响应,缓存机制,以及数据传输优化。这部分源码涉及到Quic协议(Google的快速UDP互联网...

    chrome源码学习文档

    学习源码可以了解如何实现进程间通信(IPC)和渲染进程与主进程之间的协作。 2. **Blink渲染引擎**:Blink负责解析HTML、CSS,布局页面并绘制到屏幕上。深入Blink源码有助于理解网页渲染流程,包括解析规则、布局...

    chrome 源代码

    源代码展示了如何有效地在不同进程间通信,如使用IPC(Inter-Process Communication)机制。 JavaScript引擎V8也是Chrome源代码中的重要部分,它负责解释和编译JavaScript代码,提供了高效的执行环境。V8的源码可以...

    chrome.tar

    此外,还有各种库和框架,如WebKit(以前的渲染引擎)、 Mojo(进程间通信机制)和PPAPI(插件接口)等。 为了运行和测试你的修改,你可能需要设置一个本地开发服务器,安装必要的测试框架,并学习如何使用Chrome的...

    01-Chrome架构:仅仅打开了1个页面,为什么有4个进程?_For_vip_user_0011

    同时,通过进程间通信(IPC)机制,它们协同工作,提供高效的网络请求、页面渲染和JavaScript执行。 对于开发者而言,理解Chrome的多进程架构有助于优化Web应用性能,排查问题,以及实现更安全的编程实践。例如,...

    chrome实现窗口的源码

    - **切换**:用户在多个标签间切换,源码中应有处理这种事件的逻辑,切换时会激活相应的渲染进程。 - **拖放**:Chrome允许用户通过拖放来重新排列标签,这需要处理鼠标事件和UI更新。 - **多标签策略**:Chrome...

    python selenium chrome 多开 多线程

    3. **Chromedriver**: Chromedriver是Chrome浏览器的驱动程序,它实现了WebDriver协议,使Selenium能与Chrome通信。为了运行多个浏览器实例,我们需要多个独立的Chromedriver实例。 4. **PhantomJS**: PhantomJS是...

    Google Chrome 浏览器架构解析及相关特性分析

    #### 进程间通信 - **通信方式**: - 使用 named pipes/socket pair 作为 IPC (Inter-Process Communication) 通信通道。 - 主要采用异步通信方式,但也会在必要时使用少量的同步通信。 - 一些数据通过 Shared ...

    chrome app

    4. APIs:Chrome App提供了许多原生API,如Chrome Storage API用于持久化数据存储,Chrome Messaging API用于应用间的通信,以及System API获取设备信息等。这些API让Chrome App能更好地利用硬件资源和系统功能。 5...

    google chrome源码目录介绍

    11. **ipc**:进程间通信的基础库,Chrome的多进程架构依赖于它来实现高效的数据传输和跨进程通信。 12. **media**:包含多媒体处理代码,如音频和视频解码,确保Chrome能良好支持多媒体内容。 13. **native_...

Global site tag (gtag.js) - Google Analytics