Android Vsync 原理浅析
Preface
Android中,Client测量和计算布局,SurfaceFlienger(server)用来渲染绘制界面,client和server的是通过匿名共享内存(SharedClient)通信。
每个应用和SurfaceFlienger之间都会创建一个SharedClient,一个SharedClient最多可以创建31个SharedBufferStack,每个surface对应一个SharedBufferStack,也就是一个Window。也就意味着,每个应用最多可以创建31个窗口。
Android 4.1 之后,AndroidOS 团队对Android Display进行了不断地进化和改变。引入了三个核心元素:Vsync,Triple Butter,Choreographer。
首先来理解一下,图形界面的绘制,大概是有CPU准备数据,然后通过驱动层把数据交给GPU来进行绘制。图形API不允许CPU和GPU直接通信,所以就有了图形驱动(Graphics Driver)来进行联系。Graphics Driver维护了一个序列(Display List),CPU不断把需要显示的数据放进去,GPU不断取出来进行显示。
其中Choreographer起调度的作用。统一绘制图像到Vsync的某个时间点。
Choreographer在收到Vsync信号时,调用用户设置的回调函数。函数的先后顺序如下:
CALLBACK_INPUT:与输入事件有关
CALLBACK_ANIMATION:与动画有关
CALLBACK_TRAVERSAL:与UI绘制有关
Vsync是什么呢?首先来说一下什么是FPS,FPS就是Frame Per Second(每秒的帧数)的缩写,我们知道,FPS>=60时,我们就不会觉得动画卡顿。当FPS=60时是个什么概念呢?1000/60≈16.6,也就是说在大概16ms中,我们要进行一次屏幕的刷新绘制。Vsync是垂直同步的缩写。这里我们可以简单的理解成,这就是一个时间中断。例如,每16ms会有一个Vsync信号,那么系统在每次拿到Vsync信号时刷新屏幕,我们就不会觉得卡顿了。
但实现起来还是有点困难的。
多重缓冲是什么技术呢?我们先来说双重缓冲。在Linux上,通常使用FrameBuffer来做显示输出。双重缓冲会创建一个FrontBuffer和一个BackBuffer,顾名思义,FrontBuffer是当前显示的页面,BackBuffer是下一个要显示的画面。然后滚动电梯式显示数据。为什么呢?这样好在哪里呢?首先他并不是不卡了,他还是会卡。但是如果是单重缓冲,页面可能会有这种情况:A面数据需要显示,然后是B面数据显示,B面数据显示需要耗费一定时间,但是这个时间里,C面数据也请求了展示,我们可能会看到,在展示C面数据的时候,还有B面数据的残影…
下面分情况来具体说明一下(Vsync每16秒一次)。
1.没有使用Vsync的情况

可以看出,在第一个16ms之内,一切正常。然而在第二个16ms之内,几乎是在时间段的最后CPU才计算出了数据,交给了Graphics Driver,导致GPU也是在第二段的末尾时间才进行了绘制,整个动作延后到了第三段内。从而影响了下一个画面的绘制。这时会出现Jank(闪烁,可以理解为卡顿或者停顿)。那么在第二个16ms前半段的时间CPU和GPU干什么了?哦,他们可能忙别的事情了。这就是卡顿出现的原因和情况。CPU和GPU很随意,爱什么时候刷新什么时候刷新,很随意。
2.有Vsync的情况

如果,按照之前的前提来说,Vsync每16ms一次,那么在每次发出Vsync命令时,CPU都会进行刷新的操作。也就是在每个16ms的第一时间,CPU就会想赢Vsync的命令,来进行数据刷新的动作。CPU和GPU的刷新时间,和Display的FPS是一致的。因为只有到发出Vsync命令的时候,CPU和GPU才会进行刷新或显示的动作。图中是正常情况。那么不正常情况是怎么个情况?我们先来说一下双重缓冲,然后再说。
3.双重缓冲
逻辑就是和之前一样。多重缓冲页面在Back Buffer,然后根据需求来显示不同数据。但是会有什么问题呢(这就是2中提到的问题)?

首先我们看Display行,A页面需要了两个时间单位,为什么?因为B Buffer在处理的时候太耗时了。然后导致了,在第一个Vsync发出的时候,还在GPU还在绘制B Buffer。那么,刚好,第一个Vsync发出之后很短的时间,A页面展示完了,B Buffer的也在一开始的时候就不进行计算了。那么接下来的时间呢?屏幕还是展示着B Buffer,这时候就会造成Jank现象。他不会动,因为他在等下一个Vsync过来的时候,才会显示下一个数据。
那么,如图,在A Buffer过来的时候,展示B页面的数据。这个时候!重复了上一个情况,也是太耗时了,然后又覆盖了下一个Vysnc发
出的时间,再次造成卡顿!依次类推,会造成多次卡顿。这个时候就有了三重缓冲的概念。
4.三重缓冲

首先看图。我们看到,B Buffer依旧很耗时,同样覆盖了第一个Vsync发出的时间点。但是,在第一个Vsync发出的时候,C Buffer站了出来,说,我来展示这个页面,你去缓冲A后面需要缓冲的页面吧!然后会发生什么?然后就是出现了一个Jank…,但是这个Jank只在这一个时间单位出现,是可以忽略不计的。因为之后的逻辑都是顺畅的了。依次类推,除了A和B 两个图层在交替显示,还有个“第三者”在不断帮他们两个可能需要展示的数据进行缓冲。但是注意了:
只有在需要时,才会进行三重缓冲。正常情况下,只使用二级缓冲!
另外,缓冲区不是越多越好。上图,C页面在第四个时间段才展示出来,就是因为中间多了一个Buffer(C Buffer)来进行缓冲。
但是,虽然谷歌给了你这么牛逼的前提逻辑,实际开发中你写的APP还是会卡,为什么呢?原因大概有两点:
1.界面太复杂。
2.主线程(UI线程)太忙。他可能还在处理用户交互或者其他事情。
Android Vsync 原理浅析的更多相关文章
- Android IdleHandler 原理浅析
IdleHandler:空闲监听器(就像我没事做了,在群里发了个表情,这时候其他人就知道我很闲了) 在每次next获取消息进行处理时,发现没有可以处理的消息(队列空,只有延时消息并且没到时间,同步阻塞 ...
- Android-Binder原理浅析
Android-Binder原理浅析 学习自 <Android开发艺术探索> 写在前头 在上一章,我们简单的了解了一下Binder并且通过 AIDL完成了一个IPC的DEMO.你可能会好奇 ...
- HTTP长连接和短连接原理浅析
原文出自:HTTP长连接和短连接原理浅析
- Android root 原理
Android root 原理 0x00 关于root linux和类Unix系统的最初设计都是针对多用户的操作系统,对于用户权限的管理很非常严格的,而root用户(超级用户)就是整个系统的唯一管理员 ...
- NFC(6)NFC编程的几个重要类,NFC硬件启动android应用原理
用于NFC编程的几个重要类 Tag NFC 标签 NfcAdapter Nfc 的适配类 NdefMessage 描述NDEF格式的信息 NdefRecord 描述NDEF信息的一个信息段,类似tab ...
- Javascript自执行匿名函数(function() { })()的原理浅析
匿名函数就是没有函数名的函数.这篇文章主要介绍了Javascript自执行匿名函数(function() { })()的原理浅析的相关资料,需要的朋友可以参考下 函数是JavaScript中最灵活的一 ...
- android的原理,为什么不需要手动关闭程序
转自android的原理,为什么不需要手动关闭程序 不用在意剩余内存的大小,其实很多人都是把使用其他系统的习惯带过来来了. Andoird大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制 ...
- Android源码浅析(六)——SecureCRT远程连接Linux,配置端点和字节码
Android源码浅析(六)--SecureCRT远程连接Linux,配置端点和字节码 需要编译源码的同学,一般都是win+虚拟机吧,但是再虚拟机里体验并不是很好,所有市面上有很多的软件能够做到在wi ...
- Android源码浅析(五)——关于定制系统,如何给你的Android应用系统签名
Android源码浅析(五)--关于定制系统,如何给你的Android应用系统签名 今天来点简单的我相信很多定制系统的同学都会有一些特定功能的需求,比如 修改系统时间 静默安装 执行某shell命令 ...
随机推荐
- tensorflow进阶篇-4(损失函数2)
Hinge损失函数主要用来评估支持向量机算法,但有时也用来评估神经网络算法.下面的示例中是计算两个目标类(-1,1)之间的损失.下面的代码中,使用目标值1,所以预测值离1越近,损失函数值越小: # U ...
- hexo 静态页面生成后页面打不开的问题
我这里的原因是4000端口被占用了 *** hexo入门指南教程: 官方文档 用Hexo 3 搭建github blog 做一款hexo主题(进阶) 坑 1 要安装node和git 2 别忘了安装he ...
- 基于 WiFi ( Wireless Fidelity) 的室内定位技术
系统的拓扑结构 基于信号强度的定位技术(RSSI, Received Signal Strength Indication) 无线信号的信号强度随着传播距离的增加而衰减,接收方与发送方离得越近, 则接 ...
- 解决chkconfig设置开机启动时出现missing LSB的错误
0x00 主要原因是脚本不符合LSB tags规范,在#!/bin/bash下面添加如下代码即可 以tomcat为例 ### BEGIN INIT INFO # Provides: bbzhh.com ...
- 前端通信:ajax设计方案(七)--- 增加请求错误监控、前端负载均衡以、请求宕机切换以及迭代问题修复
距离上个迭代过了很长时间,中间经历了很多事情,也在每个空余时间构思了这个迭代的东西以及下个迭代要做的东西.时间周期稍微长了,望见谅. 而且,至今这个开源库的start也已经到了165个了,会支持关注和 ...
- tensorflow 导入新的tensorflow实例
因为涉及到同一台电脑多个GPU,在指定tensorflow图的时候,需要为不同的图指定不同的GPU,所以必须在导入tensorflow之前,指定可用的GPU def import_tf(device_ ...
- Supervisod的使用
原文链接:http://blog.csdn.net/xyang81/article/details/51555473 Supervisor(http://supervisord.org/)是用Pyth ...
- Windows服务设置
[服务列表]services.msc [注册服务] 描述:在注册表和服务数据库中创建服务项. 用法:sc <server> create [service name] [binPath= ...
- jQuery实现两个DropDownList联动(MVC)
近段时间原本是学习MVC的,谁知道把jQuery也学上了.而且觉得对jQuery更感兴趣,比如今早上有写了一个练习<jQuery实现DropDownList(MVC)>http://www ...
- MFC获取系统信息
一.获取系统时间 CString str,str2; CTime time; time = CTime::GetCurrentTime(); str = time.Format("%Y年%m ...