您的位置: 首页 > 技术文档 > 网络编程 > Chrome源码剖析
SQL Server2008 Resource Governor 回到列表 无缝的缓存读取:双存储缓存策略
 Chrome源码剖析

作者:duguguiyu 时间: 2009-04-02 文档类型:转载 来自:Venus神庙

第 1 页
第 2 页 Chrome的多线程模型 上
第 3 页 Chrome的多线程模型 下
第 4 页 Chrome的进程间通信 上
第 5 页 Chrome的多线程模型 中
第 6 页 Chrome的多线程模型 下
第 7 页 Chrome的进程模型
第 8 页 Chrome的UI绘制
第 9 页 Chrome的插件模型

原文:http://www.cnblogs.com/duguguiyu/archive/2008/10/24/1318363.html

1. Chrome的窗口控件

Chrome提供了自己的一个UI控件库,相关文档可以参见 这里 。用Chrome自己的话来说,我觉得市面上的七荤八素的图形控件库都不好用,于是自己倒腾倒腾实现了一套。。。

广告虽如此说,不过,Chrome的图形控件结构,我还未发现有啥非常非常特别的地方。Chrome的窗口、按钮、菜单之类的控件,都直接或间接派生自View,这个是控件基类。Chrome的View具有树形结构,其内部有一个子View数组,由此构成一个控件常用的组合模式。。。

有一个比较特殊的View子类,叫做RootView,顾名思义,它是整个View控件树的根,在Chrome中,一个正确的树形的控件结构,必须由RootView作为根。之所以要这样设计,是因为RootView有一个比较特殊的功能,那就是分发消息。。。

我们知道,一般的Windows控件,都有一个HWND,用与占据一块屏幕,捕获系统消息。Chrome中的View只是保存控件相关信息和绘制控件,里面没有HWND句柄,因此不能够捕获系统消息。在Chrome中,完整的控件架构是这样的,首先需要有一个ViewContainer,它里面包含一个RootView。ViewContainer是一个抽象类,在Window中的一个子类是HWNDViewContainer,同时,HWNDViewContainer还是MessageLoopForUI::Observer的子类。如果你看过本文第一部分描述的线程通信的内容的话,你就应该还记得,Observer是用于监听本线程内系统消息的东东。。。

当有系统消息进入此线程消息循环后,HWNDViewContainer会监听到这个情况,如果和View相关的消息,它就会调用RootView的相关方法,传递给控件。在RootView的内部,会遍历整个控件树上的控件,将消息传递给各个控件。当然,有的消息是可以独占的,比如鼠标移动发送在某个View所管辖的范围内,它会告知RootView(通过方法的返回值...),这个消息我要了,那么RootView会停止遍历。。。

在设计的时候,View对消息的处理,采取的是大而全的接口模式。就是说在View内部,提供了所有可能的消息处理接口,并提供了默认实现,所有子类只需要覆盖自己需要的消息处理函数即可。如果对MFC的消息映射有了解的话,可以知道两者的区别。MFC在设计的时候,觉得无法提供大而全的接口,因为消息总类实在太多,而且还是可扩展的,于是就有了消息映射着一套繁琐的宏。但Chrome的图形框架,显然没有做一个通用的Framework的打算,因此,可以采用这样的策略,使得子类的派生变得简单而自然。。。

每一个View的子类控件,比如Button之类的,会存储一些数据,根据消息做一些行为,并且绘制出自己。在Chrome中,画图的东西是ChromeCanvas这个类,在其内部,通过Skia和GDI实现绘制。Skia是Android团队开发的一个跨平台的图形引擎,在Chrome中负责除了文字之外,所有内容的绘制;而文字绘制的重担,在Windows中交到了GDI的手上。这样的设计会给跨平台带来一些困难,估计是由Skia实现文本绘制会比较繁琐,才会带出如此一个设计的模式。。。

另外一个历史遗留产物,就是在Windows下的图形控件,还有一些是原生的,就是说带有HWND那种传统的控件,这是Chrome身上不多的赶工期的痕迹,随着时间的宽裕,这样的原生控件会被淘汰进历史的垃圾箱,而全部变为从View派生的控件。。。

其实,对于Chrome这套控件架构我还没算摸得很熟悉,估计等到做一次插件之后会了解的更透彻,因此,只说了点皮毛,聊表心意。。。

2. Chrome的页面加载和绘制

上面这些UI控件,都是用在窗口上的(比如浏览器的外框,菜单,对话框之类的...)。我们在浏览器中看到的大部分内容,是网页页面。页面的绘制(绘制,就是把一个HTML文件变成一个活灵活现的页面展示的过程...),只有一半轮子是Chrome自己做的,还有一部分来自于WebKit,这个Apple打造的Web渲染器。。。

之所以说是一半轮子来源于WebKit,是因为WebKit本身包含两部分主要内容,一部分是做Html渲染的,另一部分是做JavaScript解析的。在Chrome中,只有Html的渲染采用了WebKit的代码,而在JavaScript上,重新搭建了一个NB哄哄的V8引擎。目标是,用WebKit + V8的强强联手,打造一款上网冲浪的法拉利,从效果来看,还着实做的不错。。。

不过,虽说Chrome和WebKit都是开源的,并联手工作。但是,Chrome还是刻意的和WebKit保持了距离,为其始乱终弃埋下了伏笔。Chrome在WebKit上封装了一层,称为WebKit Glue。Glue层中,大部分类型的结构和接口都和WebKit类似,Chrome中依托WebKit的组件,都只是调用WebKit Glue层的接口,而不是直接调用WebKit中的类型。按照Chrome自己文档中的话来说,就是,虽然我们再用WebKit实现页面的渲染,但通过这个设计(加一个间接层...)已经从某种程度大大降低了与WebKit的耦合,使得可以很容易将WebKit换成某个未来可能出现的更好的渲染引擎。。。

重用

在《梦断代码》中,有一坨调侃重用的文字。他觉着软件重用的困难一方面来自于场景本身很多变,很难设计出一套包罗万象的东西;另一方面来自于人,程序员总是瞅着别人写的代码不顺眼,总喜欢自己写一套。。。
于是,解决重用这个问题也就只有两种,写最NB人见人服无所不能的代码,或者是有很多很多NB代码共君任选。Google无疑在这两个方面做得都不错,Map/Reduce,Big Table之类的一套东西,强大到可以适合太多的场景,大大简化了N多上层应用的开发。而对开源的利用使用,使得其可以随意挑一个巨人站到他肩膀上跳舞,每看到这种场景,MS估计都会气得拍着胸口吐血。。。
Google本身在服务端的基础底层,有很深积累,随着Chrome,Android等等客户端应用的开发,客户端的积累也逐步提升,也许,拥抱开源才是MS的正道?。。。

当你键入一个Url并敲下回车后,Chrome会在Browser进程中下载Url对应的页面资源(包括Web页面和Cookie),而不是直接将Url发送给Render进程让它们自行下载(你会越来越发现,Render进程绝对是100%的名符其实,除了绘制,几乎啥多余的事情都不会干的...)。与各个Render进程各自为站,各自管好自己所需的资源相比,这种策略仿佛会增加大量的进程间通信。之所以采用,按照 这篇文档 的解释,主要有三个优点,一个是避免子进程与网络通信,从而将网络通信的权限牢牢握在主进程手中,Render进程能力弱了,想造反干坏事的可能性就降低了(可以更好控制各个Render进程的权限...);另一个是有利于Cookie等持久化资源在不同页面中的共享,否则在不同Render进程中传递Cookie这样的事情,做起来更麻烦;还有一点很重要的,是可以控制与网络建立HTTP连接的数量,以Browser为代表与网络各方进行通信,各种优化策略都比较好开展(比如池化)。。。

当然,在Browser进程中进行统一的资源管理,也就意味着不再方便用WebKit进行资源下载(WebKit当然有此能力,不过再次被Chrome抛弃了...),而是依托WinHTTP来做的。WinHTTP在接受数据的过程中,会不停的把数据和相关的消息通过IPC,发送给负责绘制此页面的Render进程中对应的RenderView。在这里,路由消息中的那个ID值起了关键的作用,系统依照此ID,能够准确的将相关的消息发送到相关的View头上,这玩意发错了地方还真不是和有人把钱错到你账户上一样,因为错收的进程基本上无福消受这个意外来客,轻者页面显示混乱,重者消化不良直接噎死。。。

RenderView接收到页面信息,会一边绘制一边等待更多的资源到来,在用户看来,所请求的页面正在一点一点显示出来。当然,如果是一个通知传输开始、传输结束这样的消息,通过序列化到消息参数里面,经由IPC发过来,代价还是可以承受的,但是,想资源内容这样大段大段的字节流,如果通过消息发过来,浪费两边进程大量空间和时间,就不合适了。于是这里用到了共享内存。Browser进程将下载到的资源写到共享内存中,并将共享内存的句柄和共享区域的大小序列化在消息中发送给Render进程。Render进程拿到这个句柄,就可以通过它访问到共享内存相关的区域,读取信息并进行绘制。通过这样的方式,即享用到了统一资源管理的优点,由避免了很高的进程通信开销,左右逢源,好不快活。。。

3. Chrome页面的消息响应

Render进程是一个娇生惯养的进程,这一点从上面一段已经可以看出来了。它自己的资源它自己都不下载,而是由Browser进程来帮忙。不过Render进程也许比你想象的还要懒惰一些,它不但不自己下载资源,甚至,连自己的系统消息都不接收。。。

Render进程中不包含HWND,当你鼠标在页面上划来划去,点上点下,这些消息其实都发到了Browser进程,它们拥有页面呈现部分的HWND。Browser会将这些消息转手通过IPC发送给对应的Render进程中的RenderView,很多时候WebKit会处理此类消息,当它发现出现了某种值得告诉Browser进程的事情,它会组个报回赠给Browser进程。举个例子,你打开一个页面,然后拿鼠标在页面上乱晃。Browser这时候就像一个碎嘴大婶,不厌其烦的告诉Render进程,“鼠标动了,鼠标动了”。如果Render对这个信息无所谓,就会很无聊的应答着:“哦,哦”(发送一个回包...)。但是,当鼠标划过链接的时候,矜持的Render进程坐不住了,会大声告诉Browser进程:“换鼠标,换鼠标~~”,Browser听到后,会将鼠标从箭头状换成手指状,然后继续以上过程。。。

比较麻烦的是Paint消息,重新绘制页面是一个太频繁发生的事情,不可能重绘一次就序列化一坨字节流过去。于是策略也很清楚了,就是依然用共享内存读写,用消息发句柄。在Render进程中,会有一个共享内存池(默认值为2...),以size为key,以共享内存为值,简单的先入先出淘汰算法,利用局部性的特征,避免反复的创建和销毁共享内存(这和资源传递不一样,因为资源传递可以开一块固定大小的共享内存...)。Render进程从共享内存池中拿起一块(二维字节数组...),就好像拿着一块屏幕似的,拼了命往上绘制,为了让Render安心觉着有成就感,Browser会偷偷帮Render把这些内容绘制到屏幕上,造成Render进程直接绘制屏幕的假象。这可就苦了屏幕取词的工具们,因为在HWND上压根就没啥字符信息,全部就是一坨图像而已,啥也取不着。于是Google金山词霸,网易有道词霸各自发挥智慧,另辟蹊径,也算是都利用Chrome做了一把广告。。。

为什么不让Render进程自己拥有HWND,自己管理自己的消息,既快捷又便利。在Chrome的官方Blog上,有一篇 解释的文章 ,基本上是这个意思,速度是必须快的发指的,但是为了用户响应,放弃一些速度是必要的,毕竟,没有人喜欢总假死的浏览器。在Browser进程中,基本上是杜绝任何同步Render进程的工作,所有操作都是异步完成。因为Render进程是不靠谱的,随时可能牺牲掉,同步它们往往导致主进程停止响应,从而导致整个浏览器停下来甚至挂掉,这个代价是不可以容忍的。但是,Windows有一个恶习,喜欢往整个HWND继承体系中发送同步消息(我不是很清楚这个状况,有人能解释么?...),这时候,如果HWND在Render进程中,就务必会导致主进程与Render进程的同步,Chrome无法控制Windows,于是,它们只能够控制Render,把它们的HWND搬到主进程中,避免同步操作,换取用户响应的速度。。。

4. 结论

整个Chrome的UI架构,就是一个权责分配的问题。可以把Browser进程看成是一个类似于朱元璋般的勤劳皇帝(详见《明朝那些事 一》...),把大多数的权利都牢牢把握在手中,这样,虽然Browser很操劳,但是整体上的协调和同步,都进行的非常顺畅。Render进程就是皇帝手下的傀儡宰相们,只负责自己的一亩三分地,听从皇帝的调配即可。这这样的环境下,Render进程的生死变得无足轻重,Render的死亡,只是少了一个绘制页面的工具而已,其他一切如故。通过控制权力,换取天下太平,这招在coding界,同样是一个不错的策略,但是,唯一的意外来自于Plugin。按照规范,Chrome的Plugin是可以创立窗口的(HWND),这必然导致同步问题,Chrome没有办法通过控制权力的方式解决这个问题,只能想些别的亡羊补牢的招来搞定。。。

出处:Venus神庙
责任编辑:bluehearts

上一页 Chrome的进程模型 下一页 Chrome的插件模型

◎进入论坛网络编程版块参加讨论

相关文章
制作Google Chrome浏览器LOGO
web标准优秀源码下载
关键字搜索 常规搜索 推荐文档
热门搜索:CSS Fireworks 设计比赛 网页制作 web标准 用户体验 UE photoshop Dreamweaver Studio8 Flash 手绘 CG
站点最新 站点最新列表
周大福“敬•自然”设计大赛开启
国际体验设计大会7月将在京举行
中国国防科技信息中心标志征集
云计算如何让安全问题可控
云计算是多数企业唯一拥抱互联网的机会
阿里行云
云手机年终巨献,送礼标配299起
阿里巴巴CTO王坚的"云和互联网观"
1499元买真八核 云OS双蛋大促
首届COCO桌面手机主题设计大赛
栏目最新 栏目最新列表
浅谈JavaScript编程语言的编码规范
如何在illustrator中绘制台历
Ps简单绘制一个可爱的铅笔图标
数据同步算法研究
用ps作简单的作品展示页面
CSS定位机制之一:普通流
25个最佳最闪亮的Eclipse开发项目
Illustrator中制作针线缝制文字效果
Photoshop制作印刷凹凸字体
VS2010中创建自定义SQL Rule
>> 分页 首页 前页 后页 尾页 页次:8/91个记录/页 转到 页 共9个记录

蓝色理想版权申明:除部分特别声明不要转载,或者授权我站独家播发的文章外,大家可以自由转载我站点的原创文章,但原作者和来自我站的链接必须保留(非我站原创的,按照原来自一节,自行链接)。文章版权归我站和作者共有。

转载要求:转载之图片、文件,链接请不要盗链到本站,且不准打上各自站点的水印,亦不能抹去我站点水印。

特别注意:本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有,文章若有侵犯作者版权,请与我们联系,我们将立即删除修改。

您的评论
用户名:  口令:
说明:输入正确的用户名和密码才能参与评论。如果您不是本站会员,你可以注册 为本站会员。
注意:文章中的链接、内容等需要修改的错误,请用报告错误,以利文档及时修改。
不评分 1 2 3 4 5
注意:请不要在评论中含与内容无关的广告链接,违者封ID
请您注意:
·不良评论请用报告管理员,以利管理员及时删除。
·尊重网上道德,遵守中华人民共和国的各项有关法律法规
·承担一切因您的行为而直接或间接导致的民事或刑事法律责任
·本站评论管理人员有权保留或删除其管辖评论中的任意内容
·您在本站发表的作品,本站有权在网站内转载或引用
·参与本评论即表明您已经阅读并接受上述条款
推荐文档 | 打印文档 | 评论文档 | 报告错误  
专业书推荐 更多内容
网站可用性测试及优化指南
《写给大家看的色彩书1》
《跟我去香港》
众妙之门—网站UI 设计之道
《Flex 4.0 RIA开发宝典》
《赢在设计》
犀利开发—jQuery内核详解与实践
作品集 更多内容

杂⑦杂⑧ Gold NORMANA V2