首先说明一下,这里面的解释并非我自己写的,而是我找到相关资料整理出来的,也算是为坛子做出点贡献,文末也分析了谷歌三个儿子和三星 i9100,希望这篇文章能在技术层面上提供一个科学的评判 android 和 ios。 如果能解决大家心中的困惑的话, 不妨给小弟加几分, 在此先谢谢大家了。 Andorid 更新了一个版本又一个版本,硬件从单核到双核到四核,系统流畅度总算基本能和 iOS 持平了。
不过人们不禁会问,为什么都是基于 Linux, 两个系统会差别如此大?为什么 iPhone 4 用单核处理器就能实现的流畅度,Android 要高端双核才能保证?
近日,Android 开发小组工程师 Dianne Hackborn 算是半官方回答了其中的一个缘由。 Dianne Hackborn 表示,从界面 UI 本身的渲染而言,
首先,Android 从第一个版本就有使用图形硬件加速,例如通知栏拖拉,对话框的显示和切换等等。只不过在 3.0 之前的版本都不是采用完整的图形硬件加速。由于 Android 不是一个统一平台,各终端存在硬件差异,系统会自动调节动画的帧数。 一个典型的例子就是, Nexus S 可以实现 到 60fps 的渲染,所以会足够流畅。但使用同样分辨率的里程碑,由于硬件(GPU)性能问题,它就无法提供足够的帧数来保证流畅了。这样,它的界面渲染帧数要低于 60 帧,我们使用起来就会偶尔感觉到 “卡”。 而且,即使为 UI 开启硬件加速,OpenGL 技术带来的内存开销会十分大,比如 PowerVR 的图形芯片,此时要消耗掉 8MB 内存,而 UI 程序本身都只要 2MB 内存,这太划不来了。所以,为了保证不同机型顺利运作,很多时候 Android 会采用 CPU 绘图运算代替硬件加速——注意,CPU 还要干别的事情, 让 CPU 来绘图只会拖慢速度。 在 Android 4.0 之前的版本,硬件加速是作为一个可选择的参数而存在(考虑到部分 APP 不支持) 。但从 4.0 开始,这个选项将会被默认启用,开发小组已针对进行优化,即使不支持硬件加速程序运行也不会出现问题。 Dianne Hackborn 最后表示,硬件加速不是提升流畅度的唯一手段。事实上 Android 开发小组已经使用很多技术例如改进渲染技术来提升流畅度,典型的例子就是 Android 3.0 的浏览器相比 2.2 有巨大进步。而随着 4.0 铺开,更多用户可以感受到这点。 Dianne Hackborn 没有评价 iOS 是如何达到流畅的。不过大家注意, 从 iPhone 3GS 开始,每一代 iPhone 的图形芯片(GPU)都相当强大 (iPhone 3GS、iPhone 4、iPhone 4S 的图形处理芯片均为同代手机最高水平) ,而且苹果 iOS 是封闭系统,我们猜测,苹果在这一方面并 没有碰到 Android 那么多烦心事儿。 苹果 A5 处理器集成的 PowerVR SGX543MP2 图形处理器性能相当强 大,几乎秒杀了 Android 阵营各类对手而另一位软件工程师和前 Google 实习生 Andrew Munn 解释说是因为 Android 系统 UI 的框架设计的问题。 在 iOS 中 UI 渲染过程具有绝对的优先等级, 当用户接触到 iPhone 的 触摸屏后,iOS 中所有的进程都将停止,系统会将所有资源用于渲染 UI 过程。 而在 Android 系统中 UI 渲染过程的优先级别却没有那么高, 也就是说当你触摸 Android 手机屏幕的时候,系统后台的程序并没有停止,仍然在继续运行之中,比如下载和查收短信,这样系统 UI 获得的资源就不够,这就是 Android 系统不流畅的原因。 由于这个原因,新发布的 Galaxy Nexus,甚至配备四核处理器的话说 EeePad Transformer Prime 平板电脑都无法保证顺滑的操作体验, 这些设备只能与 3 年前的 iPhone 顺滑程度相比, 那么 Android 团队为什么不从根本解决这个问题呢? 实际上, Android 的开发工作在第一代 iPhone 发布之前就已经开始了, 原始 Android 原型体被设计成为使用键盘手机的设备,也就是黑莓手机的竞争对手。UI 渲染优先级别在有键盘的手机上并没有那么重要。但是在 iPhone 发布之后,Android 小组为了快速推出能与 iPhone 竞争的产品, 迅速将 Android 改成触摸屏手机系统,但那时重写 UI 框架已经不可能了。因为如果这样 Android 应用市场中的所有程序将 变得不可用,这种关系将一直处于恶性循环之中。难怪乔布斯在传记中表示 Android 是偷来的产品,哪怕苹果倾家荡产也要将其消灭。 自苹果收购了乔布斯的 NeXT 之后, 花了六年把它打磨成了 Mac OS X; 又在 2005 年左右花了两年半时间,基于它制造了 iOS。从各种意义上来说, 是一个传统技术的操作系统。 iOS 它有一个基于微内核 Mach 的 Darwin 内 核 , 有一个 叫做 Cocoa Touch 的运行时 , 用的是 Objective-C 这个 C 语言的超集。而 Android 在 Linux 内核之上,集成 了一个 Java 虚拟机 Dalvik,整个应用层跑在虚拟机之上,而开发语言用的是 Java。 事实上双方的选择都是很有道理的。苹果有 Mac OS X 十年基础,当然会选择自己最精通的技术, iOS 打造成一个传统系统,也可以无把缝链接 Mac OS X 的开发者资源。而谷歌没有任何操作系统经验,为了要争取最大的开发者资源,他们选择了世界上最大的 Java 社区。 虽然起点相同,但走出的第一步方向就已经截然相反。 究其根底,只在于 Java 只有自动内存回收,而 Objective-C 自动与手动内存回收均可(注意 iOS 只有手动内存回收)。这小小的区别导致, 谷歌只能做一个 Java 虚拟机,而苹果可以继续他们在 Mac OS X 上的经验。而这个行为导致了两者在系统流畅性上的最大区别。Java 由于只有自动内存回收, 系统会在任意时间停掉所有进程开始回收内存,这个过程是人类可以感受到的数百毫秒。而 iOS 由于可以手动管理内存,可以在用户操作的间歇由程序员进行回收,用户不会在频繁使用过程中感受到停顿。 在日常使用中这个停 顿其实是可以忍的, 但是在游戏过程中这个停顿是不可以忍的, 比如想像一下一只愤怒的小鸟在空中停顿了零点几秒再继续飞行。 谷歌事实上意识到了这个问题,于是它在 Android 2.3 版本中大修了这个问题并将之作为一个特性大书特书。且抛开 2.3 的普及性不谈, 单说这个大修的行为,也并没有修好这个问题。于是谷歌抛出了第二个在开发上的修补: 引入 C/C++ NDK。 可以说到了这一步, Android 整个内核往上的应用层才有了与 iOS 抗衡的实力, 可惜时间已经过去了近四年,iOS 积累了十五年,Android 刚刚起步。 而在内核之下呢?基于微内核 Mach 的 Darwin 对比当今服务器主流 Linux 又如何?当年 Linux 创始人曾经与某位牛人吵过一场著名的架, 正是关于微内核与内核对比, Linus 一直到现在都认为微内核只是纸上谈兵而在现实中解决不了实际问题。在这场吵架之后的岁月,坚持 内核的主流系统只剩下 Linux 一家, 而微内核系统已经延展到了基于 SVR4 的 IBM AIX/HP-UX, GNU/Hurd, Mac OS X, Blackberry QNX, Windows(是的,你没有看错)。Time will tell,这句话从来都没有错。 Android 三方 ROM 所困扰的驱动问题,正是 Linux 内核的最大局限, 植根于骨子的病是治不好的。
下面是第三位谷歌内部工程师的关于 Android 图形系统的一些观点。
1. Android 一直在使用硬件加速。实际上从 1.0 版本之后,所有的窗口元素的合成与显示都是通过硬件完成的。
2.这意味着许多你所看见的动画都是被加速过的:按钮的显示、通知 栏下拉的阴影、不同 Activity 之间的切换动画、弹出窗口以及提示框 的显示和隐藏等等等等。
3.Android 以前使用软件方式(与硬件加速相对应)来控制各个窗口元素的渲染,例如下图的 UI,其中包括四个窗口组件:状态条、壁纸、 桌面上的的启 动器、以及菜单。如果其中一个元素更改了自身的内 容,例如高亮一个菜单条目,对于 3.0 之前的版本,系统使用软件方式来绘制新的内容,然而并非所有的元素都需要被重新绘制,同时各个窗口元素的拼接也是通过硬件方式完成的。类似的,任何窗口的移动:例如菜单的上下运动是完全通过硬件方式渲染的。
4. 现在我们来关注窗口元素的内部渲染,实际上为了达到每秒 60 帧 的 FPS,你并不一定需要硬件加速。帧速取决于要显示的像素的数量 以及 CPU 的速度。比如说,二儿子完全可以以 60FPS 的速度在它 800*480 分辨率的屏幕上完成任何普通的原生 UI 动画,例如列表的滚动等, 完全没有问题。 而最初的 Droid 系列却很难达到这样的速度。
5.在 Android3.0 中可以实现窗口的”完全”的硬件加速绘制。而在 Android 4.0 中也没有引入更多的功能。 从 3.0 开始,如果在你的应 用中设置了一个标志允许硬件加速, 那么此时所有的窗口的绘制都会 交给 GPU 来完成。在 Android 4.0 中最主要的改变就是:在面向 Android4.0 或更高版本的应用中,硬件加速是被默认开启的,再也不需要在配置文件中设置 android:handwareAccelerated=”true”.(而我们 不允许之前的应用默认打开硬件加速,是因为光靠硬件加速,无法很 好的完 成某些特殊的绘制操作; 同时在应用需要其中一部分 UI 更新 的时候,会影响其的一些表现。对于目前现有的很多应用,强制开启硬件加速,会明显的中断应用的运行)
6.硬件加速并不如大家所认为的那样完美。例如在基于 PVR 驱动的设备上(比如二儿子跟三儿子),光是在进程中开启 OpenGL 就得占用 8M 的 RAM。 比一般进程的 2M 的开销实在是巨大。 对 RAM 是有限的,一大部分被拿去绘制,那么其他正在运行的进程就会因为缺少内 存而出问题,比如降低应用间切换的速度。
7.由于 OpenGL 的额外开销,我们最好不要过多的使用其进行绘制。 比如我们现在在做的一些工作,就是为了让 Android 4.0 能在不使用 硬件加速的情况下流畅的在二儿子上使用: 这样我们就不需要在系统进程中浪费 8MB 的内存用,也不需要在手机进程中浪费额外的 8M 内存,或 者是在系统 UI 进程中的 8MB 内存等等等等。相信我,你不会注意到用 OpenGL 来绘制一些类似状态栏或是华丽的动画是完全没有好处的。
8.硬件加速并非流畅 UI 的“解药”。我们为了 UI 的流畅尝试了很多不同的方法,比如说在 1.6 中引入的对前台/后台进程的调度策略,在 2.3 中的对输入系统的重写,”严厉模式”的使用,并发的垃圾回收机制,载入器等等。如果你想达到 60fps 的帧速,你只有 20 毫秒的时间来处理每帧的内容。这时间实在不长,光是在 UI 进程中读取存储卡的操作产生的延时就会大于这个时限,尤其是在写操作的时候。
9.举些最近发现的一些影响 UI 流畅度的例子:我们注意到在二儿子上,使用 4.0 时列表的滚动就不如使用 2.3 时流畅。而导致这个现象的原因则是计时器的轻微漂移:有些时候应用正在接收触摸事件并在屏幕上绘制,而在上一个动作还没完成的的时候,就接受到下一个事件并开始绘制,导致它丢失了当前这帧。尽管发生这种现象的时候,帧速能达到稳定的 60FPS.(当然,这个问题已经修正)
10.当人们比较 Android 跟 IOS 上浏览器的滚动流畅度的时候,他们 所看见的差别并非开没开启硬件加速所导致。 最初的时候,Android 使用了一种完全不同的渲染策略,并做了一些折中:网页被转换成一 个“显示列表”, 持续的在屏幕上进行绘制, 而非使用块 (Tiles)的形式。 它有一个优点: 就是在滚动或是缩放的时候不会发生有的块还没被渲 染出来的现象(译者注:早期的 IOS 上这种现象非常明显,快速滚动 到底部时要等一会网页才会一块一块的绘制出来)。 而这个方法的不 给力之处就在于页面复杂的时候, 帧速就明显低了。 例如 Android3.0, 浏览器中现在开始使用块的方式进行渲染,于是它可以在滚动或是 放大的时候保持一个稳定的帧速, 自然也会出现新的块没有被立即渲 染出来的情况。 而每个块都是以软件方式绘制的,我相信在 IOS 中 也是这样的。(在 3.0 之前的版本中,没有开启硬件加速,基于块的策略也可以使用。而且如我之前提到的, 二儿子可以很容易的达到 60FPS)
11.硬件加速不能如大家所想奇迹般的让绘制的问题统统消失。GPU 的性能就是一个很重要的限制。最近一个很有趣的例子:基于英伟达 的 Tegra2 的平板 可以很容易的以 60FPS 的速度访问 2.5 次 1280*800 分辨率的屏幕中的任何一个像素。现在考虑到在 Android 3.0 中切换 到所有应用列表的情形:你需要绘制背景(1x 所有的像素)、接着是 快捷方式和桌面小工具(假设内容不多,花费 0.5x),接着是所有应用 的黑色背景(1x),接着是所有应用的 ICON(0.5x)。 显然,我们已经 超过了原先的预算了, 而此时我们还没完成各个独立窗口元素的拼接 并做最后的显示。想要取得 60FPS 的动画,Android 3.0 以及后续版 本使用了一系列的小技巧。 其中主要的一个就是: 它将所有的窗口 元素平铺在一个层中,而不是挨个拷贝到 CPU 的缓存中。但即使是 这样,我们已然超出预算,幸好我们使用另一个技巧:因为 Android 中的背景是一个独立的窗口元素,我们可以将它设置的比屏幕更大来放置整幅位图,现在,用户开始滑动,背景跟着运动,此时并不需要任何特殊的绘制,仅仅是移动窗 口即可,而由于这个窗口是在一 个平铺层上,我们甚至不需要用 GPU 来将这个窗口元素组织到屏幕 中输出。
12.随着屏幕分辨率的不断升高, 能否达到 60FPS 跟 GPU 的速度尤其是内存总线带宽息息相关。事实上,如果你想要提升硬件的效力,特别注意要提升内存总线的带宽。很多时候 CPU(特别是带有完美的 NEON 指令集的 CPU)会比内存总线块的多。 有些人认为盖世兔已经有了一个非常流畅的 UI 并指出他们已经超越 三儿子并做了很多改进。事实上,大家忽略了很多设备的差异,盖世 兔的屏幕是 480*800 而三儿子是 720*1280。 如果二儿子在它 480*800 的屏幕上都能达到 60FPS,拥有更 NB 的 CPU 的盖世兔必须得同样流畅嘛。 而两者之间最大的差别就是三儿子需要同时绘制 2.4 倍于盖世兔的像素。 这相当于在单核上提升到 2.4 倍的速度。 (需要指出在 UI 渲染的时候,多核是没有意义的,因为渲染必须要在一个进程中完成,无法并行) 这就是为什么硬件加速非常重要:随着像素的提升,GPU 通常能更好的处理图像的运算。事实上,这是我们在 Android 中引入硬件加速 的最大动力。在 720*1280 的屏幕上,现有的 ARM CPU 达到 60FPS 很吃力,但是通过 GPU 渲染就不同了。同样,在与盖世兔的比较中, 同时打开没有硬件加速的应用,在三儿子中无法达到盖世兔同样的 60FPS,是因为它得渲染 2.4 倍于盖世兔的像素。 在最后,还得提及 GPU 的另外一个优势:许多绘制的效果变得更加 容易。比如你要以软件形式绘制一个位图,你除了设置一个位移,不能做任何事。 仅仅是缩小就 得花上相当多的时间进行渲染。 而在 GPU 中,此类转换则相当容易。这就是为神马新的默认主题 Holo 使用硬件加速绘制背景。而在没有开启硬件加速的应用中,此类背景会自动去掉~