标签:blinkon slimming paint blink scheduler oilpan serviceworker
摘要:BlinkOn3会议11月份刚在Google的MountainView办公地点举行,本文选取了BlinkOn3的几个话题,如为Blink绘图瘦身的SlimmingPaint,多优先级的Blink调度器,Oilpan垃圾回收机制,用JavaScript开发新的DOM特性等等,和大家一起分享Blink项目目前取得的进展和下一步发展方向。
原创文章,转载请以链接形式注明原始出处为http://blog.csdn.net/hongbomin/article/details/41091679.
根据BlinkOn3会议讨论的话题,我们大致可以了解到Blink项目的最新进展和下一步的发展方向,总体上来说,优化Blink在移动平台的图形性能和内存消耗方面仍然是目前Blink项目的重中之重,也是Chromium整个项目的重中之重,此外,提升WebApp使用体验、提高代码安全性和健壮性方面以及持续的代码重构,一直以来都备受重视。这里我们选取了其中几个话题,尝试从所要解决的问题及其采用方案的角度对其作简要分析。
Slimming是减肥的意思,这个词用的很形象。一直以来Blink项目都努力提高绘图的性能,比如引入实现端绘图(--enable-impl-side-painting)技术将页面内容的绘制工作从主线程中解放出来,由Compositor线程将繁重的绘制任务安排在单独的线程中进行,而主线程仅仅需要把页面内容的绘图命令录制成SkPicture,交给Compositor线程就可以了,比起将内容直接绘制成像素,录制命令的开销要小的多,尽管实现端绘图可有效地减轻主线程的负担,但纵观整个Blink的渲染流水线,还存在不少问题。
首先,Blink页面中的渲染层管理问题。Blink一直沿用了早期WebKit硬件加速的页面渲染框架,为了使页面能够按正确的次序显示页面中重叠、半透明、CSS动画等内容,Blink会将页面分层多个RenderLayer构建RenderLayer树,每个RenderObject都属于一个RenderLayer,但一个RenderLayer可能包含多个RenderObject。从页面的合成角度看,出于内存方面的考虑,不是每个RenderLayer都需要自己独立的后端存储,所以便有GraphicsLayer,RenderLayer与GraphicsLayer的关系类似于RenderObject与RenderLayer的关系,也就是,一个RenderLayer必定属于GraphicsLayer,而GraphicsLayer可能包含多个RenderLayer。在页面发生更新时,Blink需要做的事情是遍历整个RenderLayer树,计算出有哪些RenderLayer需要更新,再调用RenderLayer::paint将更新的内容绘制到所属的GraphicsLayer上。不难看出,Blink不仅要计算更新的区域,还要维护RenderLayer树以及GraphicsLayer树。
其次,页面存在潜在的基本合成问题。对于以下的HTML页面,将会得到错误的合成结果:
<html> <body> <canvas id="canvas"style="background:red;width:100px;height:100px"></canvas> <div id="overlap"style="background:green;margin-top:-50px;margin-left:50px;width:100px;height:100px"></div> </body> </html>
正确的合成结果应该是绿色的矩形叠加在红色的矩形之上。但Blink的输出是,红色的总是在绿色之上,原因就是红色的<canvas>元素有自己独立的RenderLayer,而<div>元素没有独立的RenderLayer,而是与<body>共享同一个RenderLayer,<div>元素本身是不会参与overlap检测的。
Slimming Paint目标就是要重写整个Blink和Chromium的渲染流水线,解决上述提到的两个问题,同时提高命令录制和绘制的性能。这是一次比较大的架构调整,Blink代码关于绘图方面的逻辑会有比较大的改动:
大致的流程如下图所示:
在新的渲染流水线中,Blink不用再维护RenderLayer和GraphicsLayer,唯一要做的是,通过每个RenderObject的Paint生成整个页面内容的PaintList和为Compositor提供必要的分层提示信息。PaintList类似于DisplayList,包含了绘制次序,绘制命令,变换矩阵,Clip区域等信息,而Compositor从这些信息中完全能够计算出如何对页面进行分层。
Blink Scheduler是由Google伦敦团队主导的一项优化,旨在解决任务队列的“拥堵”问题,简而言之,一些高优先级的任务被一些优先级低、执行时间过长的任务阻塞,导致高优先级的任务延迟执行,从而影响整体的流畅度。
Blink主线程的任务来自系统中各个模块,如下图所示,所有的这些任务都是由主消息循环统一调度。每当向消息循环发布一个任务时, 这个任务会被添加到任务队列的队尾,消息循环会按照先进先出(FIFO)的顺序依次从任务队列中取出一个任务,然后再执行,直到任务队列为空。所以,如果一个高优先级的任务到达消息循环后,它必须等待在它之前所有的任务都执行完毕后才有机会得以执行。
Blink Scheduler通过引入多优先级任务队列,正在尝试解决上述问题。每个任务都有一个优先级,消息循环按照优先级将任务添加到相应的队列中,如果单纯只是对每个任务指定一个优先级,可能带来一个问题就是如何解决任务之间的依赖性,为此,Blink将任务划分为三个类别:1)Compositor;2)Default;3)Idle,其中Compositor任务的优先级最高,Default任务次之,Idle任务优先级最低。按优先级执行任务。然而,如果静态地指定Compositor任务总是最高的,页面加载的性能降低了14%,显然也是不可取的。
所以,Blink Scheduler采用了上下文感知的动态优先级策略,例如,
在实现方面,Blink Scheduler对Chromium的base/message_loop底层代码将会有较大的改动,还会在content层次上增加对BlinkScheduler的抽象,实现多优先级任务队列的调度,支持将任务发布到不同的任务队列上,支持选择下一个待处理的任务队列,支持动态修改优先级策略等,如下图所示:
Oilpan项目引入的背景是,Chromium在浏览网页时,有时会发生莫名奇妙的内存泄露问题。根据Blink的内存泄露检测器(LeakDetector)给出的数据显示,ChromiumWebView在访问946个网站之后,有294个WebCore::Document对象没有得到释放。
在Oilpan项目之前,Blink和Chromium都采用引用计数技术(referencecounting)来管理内存,每个对象内部都一个引用计数,表明当前对象被引用了多少次,当引用技术归零时,对象就会被自动释放掉,这种方式一直以来都存在一个缺陷就是循环引用问题,就A引用了,B又引用了A,最后导致A和B都没有机会释放,此外,C++中启用引用计数还存在其他几个方面的问题:
尽管引用计数存在上述一些问题,但它很轻量级,仍然是C++程序中广泛使用的自动内存管理计数。Blink项目并不满足这种轻量级的内存管理方法,于是Oilpan项目提上日程,要实现对Blink对象的自动回收机制。比起引用计数技术,Oilpan垃圾回收器确实是个庞然大物,它实现了一个一般只有虚拟机才需要的高级特性,然而Blink项目力求精益求精,追求最好!
Oilpan实现了一种跟踪式的垃圾回收机制,具有如下特点:
截止到目前,Oilpan基础框架已经比较稳定,modules/中所有对象默认都启用了Oilpan,但Node层次结构还未正式启用。
关于Oilpan,大家可能比较关心它的性能和内存开销问题,评价Oilpan是否成功有三点,第一,比引用计数更快,第二,不能使性能变差,第三,不会增加内存使用量的峰值。根据最新的性能和内存使用评测结果来看,执行效率和内存使用的峰值都不是问题,但因GC带来的暂停时间是个问题,特别是对于一些动画的benchmark,在Nexus7设备上有些GC操作要花费超过50ms,显然是不能接受的,下一步的方向就是优化stop-the-world所耗费的时间。
ServiceWorker是一项比较新的Web技术,是Chromium团队在吸收了ChromePackaged App的Event Page机制,同时吸取了HTML5 AppCache标准失败的教训之后,提出一套新的W3C规范,旨在提高WebApp的离线缓存能力,缩小WebApp与NativeApp之间差距。
目前Web App在离线缓存方面并不完善,尽管有HTML5 AppCache标准允许Web开发者通过manifest文件指定WebApp可以被浏览器缓存的文件清单,但由于这套机制不够灵活,存在较大的局限性,被很多Web开发者抱怨。ServiceWorker试图改变这一现状。
ServiceWorker可以看做Web Worker规范的一个有趣的应用,类似于SharedWorker,专为WebApp离线使用而设计的,它是一段可以安装在Web网站上的JavaScript代码,它运行在一个独立的Worker上下文中。当访问网站时,ServiceWorker会监听网络请求,如资源获取,更新等,甚至在离线情况都能收到这些事件,Web开发者可以决定在ServiceWorker的代码中如何处理这些事件。
ServiceWorker一个典型的应用情景是,当访问一个网站时,在有可用网络的情况下,浏览器从服务器端下载资源,将网页显示给用户,但在网络不可用的情况,即离线状态,如果再次访问这个网站,那么浏览器会报告404错误,有了ServiceWorker,情形就好的多了,ServiceWorker可以监听网络请求事件,一旦发现当前处于离线状态,ServiceWorker会转而从缓存中读取一些内存展现给用户,让用户即时在离线状态下,也可以使用网站的服务,大大增强了Web页面的离线能力。
安装了ServiceWorker的页面称为“受控页面”,ServiceWorker是浏览器到服务器端之间的一个中间层,可以转接所有的网络请求,包括XMLHttpRequest请求加载资源,也可以创建和调出所有存储在本地缓存的数据,ServiceWorker和受控页面之间还可以相互发送消息。
用C++实现过DOM API的同学应该都有亲身体会,为Blink新增加一个DOM特性确实是件比较繁琐的事情,为了实现一个DOM新特性,你需要修改IDL,IDL解释器会生成一堆C++代码,然后还得用C++根据固定的模式编写具体特性的实现代码。众所周知,C++代码难写,需要仔细的考虑每个对象的生命周期,稍有不慎,内存问题最终会导致安全问题,这样导致开发效率低下,而且日后维护成本也大。
Blink-in-JS使Blink开发者使用JavaScript实现DOM新特性成为可能,其基本思想就是用C++实现DOM的核心部分导出一组JSAPI作为基础库,基于这些已有的JavaScriptAPI,尽可能使用JavaScript实现DOM的其他部分,例如XSLT,editingAPI,DOMWindow.atob/btoa以及ScriptRegexp等。以XSLT为例,Blink的C++实现很复杂,但实际上用的并不多,主要是一些企业级用户,对于这样一类不是很受欢迎或者很快将会过时的API,Blink-in-JS可以将复杂的C++实现从Blink代码库移除掉,取而代之使用JavaScript去实现这类API。
Blink-in-JS可以帮助Blink开发者提升开发效率以及代码的可维护性,但副作用有可能是导致那些用JS实现的API运行时性能和内存开销比C++的要多,所以,对于性能要求较高的API,建议还是用C++实现更好。对于内存开销问题,被JIT过的JS代码大小是C++二进制代码的20倍之多,相应的解决办法是,启用JavaScript代码的延迟编译,只有当app请求调用这个特性时,才开始编译它的JavaScript代码,而且编译过的JS代码使用完了之后会被丢弃掉,下次请求时需要再重新编译,这实际上只是折中方案。
以DOMWindow.atob为例,Blink-in-JS的编程模型如下:
// WindowBase64.idl interface WindowBase64 { [ImplementedInJS]DOMString atob(DOMString str); }; // WindowBase64.js installClass(“WindowBase64”, function() { return {atob:function atob(str) { // Here |this| isequal to |window|. returnbase64Encode(str); }}; });
所以,理论上Blink-In-JS可以达到和Chrome Extension相同的安全级别。
在过去半年时间内,Blink项目演进速度还是相当快的,仅从7月份到9月份,代码行数从264万增加到269万,每天平均有52个commit,Blink社区共收到151个Intents的贡献请求,其中Google占了51%,剩余的来自整个开源社区,这个数字说明Blink已经发展的相当不错,社区的参与积极性还是比较高的。
截止到11月份,Blink已经落地的特性有:
还未落地的特性有:
本文简要地介绍了目前Blink项目中几个比较重要的子项目,比如为了进一步提升渲染性能而重写整个Blink/Chromium渲染流水线,为Blink绘图瘦身的SlimmingPaint技术,优化高优先级任务处理的BlinkScheduler,还有解决不明内存泄露问题的Oilpan自动垃圾回收器,还有Blink-in-JS实现了开发效率和代码安全的双提升,以及ServiceWorker能够灵活地支持WebApp离线能力,除了上面提到的,还有一些没有特别做介绍,但对后续Blink项目演进有比较大影响的变化,例如,和Chromium代码库的合并,如果只是文件目录的合并倒也没有太大变化,但如果是源码级别的合并,改动就大了,包括合并base和WTF基础库等,还有ProjectWarden项目成立的初衷就是专门负责重构Blink代码,简化排版和绘图的流程,清理Blink中各种诡异的问题,如Repaint-after-layout, 排版过程中不能修改RenderTree等。这些变化已经发生或者正在发生,使Blink项目得以快速向前演进,下一步技术方向仍然是以性能为主,尤其是针对移动设备的,以构建WebApp平台为基本出发点,逐步缩小与NativeApp的差距,与此同时,通过代码重构和架构调整,提高Blink代码的可维护性、可靠性和安全性,从而提高开发效率。
注:本文所有图片均来自BlinkOn会议的Slides,版权归原作者所有。
原创文章,转载请以链接形式注明原始出处为http://blog.csdn.net/hongbomin/article/details/41091679.
BlinkOn2所有PPT资源汇总:http://bit.ly/blinkon2
BlinkOn3所有PPT资源汇总:http://bit.ly/blinkon3
Chromium Blink项目最新技术报告和下一步发展方向
标签:blinkon slimming paint blink scheduler oilpan serviceworker
原文地址:http://blog.csdn.net/hongbomin/article/details/41091679