您的位置:首页 > 移动开发 > Android开发

关于youtube上Android Performance Patterns的总结(部分)

2016-04-24 20:21 169 查看
1.熟悉android studio关于Logcat,Memory,CPU,GPU,Network分析窗口的使用。一旦你配置的内存突然下降,那么应该是GC在发挥作用。这些垃圾收集活动通常不会太大影响性能,但是短时间内频繁的出现,会迅速消耗帧时间,还是会导致性能问题的。

2.内存泄露:指的是应用不再使用的对象,但是垃圾收集没有把它们辨认出来。结果是它们一直留在你的内存里。

android运行环境中的内存堆:



android runtime内存堆被有效的划分为不同的区块,根据配置的类型,还根据系统为将来的垃圾收集活动对这些配置的最佳整理。新的对象被配置时,会考虑到这些特点,来决定哪一个区块最合适这个配置。

3.GC的两个主要原则:

1.找到程序里以后都不会使用的数据对象。

2.重新收回这些对象占用的资源。

知道两点:

1.在规定时间内应用垃圾收集时间越长,那么剩下的用于16ms内完成光栅化的逻辑处理时间就更短。如果有连续的大量垃圾收集,或者长时间的垃圾收集,可能会超过16ms,就会导致用户视觉上的卡顿。

2.要知道你的码流可能会执行一些工作,迫使GC发生的更加频繁,或者持续时间更长,比如,在向内部循环中进行一大堆重要对象配置时,就会花费很长时间。这一大堆对象就会污染内存堆。

4.内存流失:在短时间内配置大量的对象,并将它们极短时间内进行释放,就会出现内存流失。如果在内存监控中,看到有内存抖动,那么八九不离十从那里下手。

解决办法:

1.要确保没有在内循环内,为了明显原因配置对象。试着将它们移出到循环之外,或者直接避免它们。还有onDraw函数中也是一样(本质相同)。

2.如果非要创建对象,可以考虑对象池模式。实际上,你会有一个用于配置一组对象的对象池,你的代码不必每次都到堆里去,它可以从内存池里抓取可获得的对象。



这种模式的弊端:你得自己负责释放对象,在使用完要将它们释放进内存池。也就意味着对于高扰动对象,就会需要消耗一些精力,在创建和销毁时合理管理这些对象。(跟getView方法中的模式很像)。

5.关于JobScheduler API的介绍:如何在低电量情况下做事。工具battery historian。

一言以蔽之, 就是把不紧急的工作留待条件更充分的时候完成.

更好的条件包括wifi, 充电, 手机处于休眠状态等…

如果APP有符合如下情况的任务, 可以尝试使用JobScheduler机制执行任务:

可以推迟的非面向用户的任务(如定期数据库数据更新)

当充电时才希望执行的工作(如备份数据)

需要访问网络或 Wi-Fi 连接的任务(如向服务器拉取内置数据)

希望作为一个批次定期运行的许多任务

代码上所需做的工作是将相关任务放置到JobService, 并根据应用情况设置Service启动条件, 可以是如下条件:

当设备充电时启动

当设备连接到不限流量网络(wifi)时启动

当设备空闲时启动

在特定的截止期限之前或以最小的延迟完成

只有当条件得到满足, 系统才会启动计划中的任务.

只要一切执行到位, 对手机续航的提高当然显而易见.

6.关于overdraw:

过度绘制发生的原因是,硬件使用太多的周期来绘制屏幕上的像素,而这些像素到最后都不会组成图片。

现在安卓系统会自动尽量减少过度绘制,它可以试着避免绘制那些完全隐藏于不透明表面之下的项目 。

但是这项技术没有再深入发展,没有复杂的定制视图,还不能覆盖onDraw方法。这些情况下,系统无法了解你是如何绘制内容的,从而很难知道自己应该避免什么。

解决办法:通过使用canvas.cliprect API帮助系统好观察到这一过程。这个功能允许你为自己给出的视图规定可绘制边界,只有矩形框内的项目可以被绘制。

这个API还能保护CPU和GPU的性能:

CPU:每一条canvas绘制命令,将它们提交给OpenGL ES进行绘制时,都会有一点点额外负担。任何clipRect之外的绘制命令都不会提交至硬件,也就不会产生额外负担。

现在,任何与clipRect有部分交叉的内容还是会被绘制。

这也是clipRect在GPU方面可以帮助定义排除矩形,从而从像素层面上让GPU避免为裁剪部分上色的原因。

除了clipRect,还可以使用qucikreject API,他可以让你在你的onDraw功能内部,测试clipRect的交叉部分。

可以使用GPU Overdraw工具进行监测。

7.对于绘制的工作原理:

android系统的工作原理,当更新可视化物品的时候,要记住android在你的设备上绘制图案前,都会将高级的xml文件,转换成GPU可以接受的文件,然后进行屏幕渲染。

这要借助一个内部对象,他叫做显示列表。显示列表基本上包含了所有用于GPU渲染的所需信息。

要想提升渲染系统的整体性能,布局失效最小化是一个不错的开端。



监测工具:

1.Profile GPU Rendering



2.经常使用Hierarchy Viewer,检查你的视图层次,尽量保持它的平整。

8.绘制:



按钮,或者路径等,需要被绘制到屏幕上时,它们首先需要在CPU内被转换成像素和纹理,然后才能送至GPU进行光栅化。

优化光栅化性能意味着,将尽可能多的数据存入,而且越快越好,然后留在那里,尽可能长时间不去动他。

对于常用的绘制图案,纹理,android进行了优化,不需要经过CPU进行转换,而是直接存在了GPU中,这样就减少了中间转化的时间。

9.Profile GPU Rendering:

蓝色,红色,橙色直接反映了android渲染通道的比例。

蓝色:代表了绘制时间。或者说,在java中具体花了多长时间来生成并更新你的显示列表。记住,在视图被渲染之前,它必须被转换成适合GPU的格式。简单的说,这可能仅仅是几个绘图命令,当复杂起来,我们可能需要往里的canvas对象里嵌合自定义路径。一旦完成,结果由系统生成为显示列表。蓝色记录了为所有的需要更新的视图完成这两步需要消耗的时间。上图:



如果蓝色升高,可能是:

1.一堆视图突然失效了

2.一部分自定义视图在onDraw功能里包含了某些复杂逻辑。

红色:代表了执行时间。这是android的2D渲染执行显示列表时消耗的时间。越是复杂的视图,越是需要复杂的命令让OpenGL绘制。

如果红色升高:可能是:

1.复杂的视图。

值得注意的是密集的栏目高峰,还有可能是重复上传大量视图,进行重新绘制造成的。这些视图不一定是无效的。

橙色:代表了处理时间。这是CPU告诉GPU它完成一帧渲染了。这个活动是一个封锁呼叫。因此,CPU会等待GPU的信息,来感知它接受到的指令。如果橙色高,意味着GPU在处理大量工作,导致出现了很多复杂的视图,需要很多的OpenGL渲染命令来进行处理。

10.VSYNC。

刷新频率:屏幕每秒内更新显示的次数。

帧频:GPU每秒可以绘制的帧数。例如60fps。这种情况下,帧频越高越好。

解决两个频率不同的问题:双缓冲技术,也叫后台缓冲

实际上,当GPU将一帧绘制到内存后,它会将其复制到内存副区域,也叫帧缓存区,当它绘制第二帧时,它会完成后台缓冲,帧缓存区不受影响,现在,当屏幕刷新时,它会从并不处于绘制过程中的帧缓存区进行刷新。



这就要用到VSYNC了,也叫垂直同步

帧率要一直保证你的GPU能够迅速获取它要的数据,并且有时间在下一次屏幕刷新前进行绘制。android会每隔16ms绘制刷新屏幕一次,如果帧频小于60,那么在刷新屏幕时,会检测到渲染没有准备好,那么就不会进行刷新(即保存原来的样子)。这样,我们就在32ms内看到同一帧的图像(可能更长)。

11.进入开发者模式,利用工具:“显示GPU重复绘制”进行监测。能够检测overdraw。

12.MonkeyRunner,Espresso。

13.加载图片造成的内存抖动:

1.使用对象池

2.可以指示解码器使用一个已存内存片,来将该位图载入,而不是创建一个新的位图。使用对象BitmapOptions(位图功能)中的inBitmap属性可以解决。当你将inBitmap属性分配到一个已存在的位图时,对接下来的像素数据,你的任何解码和加载指令都会重复使用那个现存的位图,而不是从堆中配置一个新的对象。



注意点:

1.对于SDK 18以下,加载的位图和重新使用的位图必须大小一致才能合理工作。 对于19以上,加载的位图比原图大或者相等。



2.虽然可以跨像素格式重新使用,这也是个多节的过程,一个简单的方法是为你的每一种像素格式使用单独的位图。这样好麻烦!

3.使用glide库,或者其他开源框架吧。

14.Pre-scaling Bitmaps:

对于生成不是原图的2的幂大小的位图。首先用inSampleSize将它转换成目标带下的2次幂。然后用inDensity和inTargetDensity将生成规格缩放为你想要的准确大小。这两个方法的结合是非常快的操作,因为inSampleSize会减少像素的数量,而基于输出密度的步骤需要对这些像素应用大小重置过滤。



实用类库:glide,Picasso。能够处理这类位图大小重置的代码,还有其他功能,比如异步解码和缓存。

15.PNG文件是android图像内容的主要部分,特别是当你的应用内有很多UI元素,而不是图片数据时。PNG它们很容易膨胀,膨胀频率高。

优化方法:

1.



2.使用WebP格式。它支持alpha透明处理,无损及有损压缩,也支持动画。事实上,WebP和有损处理步骤,只会在图片发布阶段帮助你处理大小。一旦图片已经加载至内存,它们已经被解压至正常格式,所以可以用于渲染。这意味着,所有的文件压缩只能帮你进行数据传送,而不是CPU内存使用量。一旦文件离开磁盘进入内存,有些很好的压缩保存都消失了。

16.更小的像素格式:



所谓性能,在于取舍。图片的内存大小,视觉效果,加载时间。这都是你需要平衡的,这样你的应用才能实现最佳性能。Dalvik版本时的android垃圾收集器是不可压缩的,意味着当对象被释放时,其他的对象不会为了优化以释放空间而被调整。这代表了位图的一大问题,它可能是你会在应用内实际配置的最大的连续内存区块。你堆内存中连续可用空间越少,意味着位图的配置可能失败,导致垃圾收集事件被触发,来在其他位置释放空间,所以配置最终可能成功,也可能出现内存不足错误。



这些图片在内存中如此大的原因是,在你可以使用这些JPEG或PNG文件前,它们先要被加载进入内存并解码成一种系统可以渲染的格式,就是说一旦它们载入了,它们就不再是它们的压缩格式了。并且,默认情况下,android中当图片被载入为位图时,格式默认为AGBB_8888,此外通过设置,其他格式有RGB_565,ARGB_4444,ALPHA_8.

17.提高性能,减少工作量很重要。但有时,工作时间和工作量同样重要。几个重要API:

1.AlarmManager



设置非准时警报。不必要时,不要设置准时警报。

2.SyncAdapter(同步适配器):它提供的批处理方式与非准确警报完全一致。但是他们也会给你带来网络连接检查和自动重试。

如果你的目标是API21以上,直接用功能更强大的3。

3.JobScheduler

18.自定义view:

错误:

1.浪费时间绘制那些还没改变的事物。

2.浪费时间和带宽绘制永远不会显示出来的像素。因为它们被其他物体遮盖住了。

3.浪费太长时间运行绘制函数的代码。

对于1:

记住,所有的绘制开始都要调用view.invalidate代码。

原则一:如果视图里没有任何改变,那就不必重新绘制。



原则二:永远通过一个矩形来作废。脏矩形(dirty rect),给系统的提示,告诉它视图的那个部分被改变了。遮阳系统使用这个矩形来帮助决定何时调用绘制函数。

当你的视图动画时,onDraw每秒会被调用60次。与其他大部分代码不同,绘制代码必须在UI主线程运行。

19.ANR:

通常我们怀疑的是会无限期阻塞的系统调用,比如磁盘或者网络访问。正常情况下,可以执行的很快,但是一旦硬件+软件+坏运气组合起来,他们就会爆发。

监测工具:开发者模式下的strict mode。

严格模式:

Thread Policy: 线程规则有探测较慢阻塞方法的功能。

VM Policy:探测各种内存流失的选项。

两张规则相辅相成。

如果你内存较低,一个普通的配置也会阻塞上百毫秒。很可能在你应用的主线程上,有至少一个阻塞调用,正等着导致小故障,丢帧,甚至ANR。严格模式会帮你找到他们。

20.避免在onDraw中进行配置(allocation):

在绘制函数里进行的典型配置,比如绘画,路径,字样等。可是这些类都有共同点,他们都是本地对象的封装器。android系统的2D绘制系统依赖于一个叫Skia的图形处理函数库。Skia是用c++编写的。android.graphics里的很多类,实际上都是本地c++对象的封装器而已。而且c++对象有析构函数,在你回收某个对象的内存之前,你要明确的调用析构函数。这意味着要运行终结器(finalizers),这对性能是非常不好的。而且析构函数必须,和其他的事一起,在本地堆锁上同步。所以总有可能,他们会阻塞UI主线程,时间长到会丢帧。换句话说,持续的创建并丢弃图像对象,本质上就是告诉系统,希望应用在不可测的时间间隔内被不定时长的打扰。

解决方法:本质,不要在onDraw函数中new太多对象。利用android studio里面的重构工具。使用Extract Field(提取域)来将这些对象移出绘制函数,并放进可以被重新使用的类的主体内,如果可能的话,让这些域保持静态。这样,你可以重新使用你的类的多实例中的对象。特别是当你的视图在列表项中使用时,这是个很好的方法。因为这种情况下它会被多次创建。

21.hidden cost of transparency:

alpha透明组合,是帮助应用畅销的一个酷炫效果。

当你渲染不透明元素时,每个像素只需要写入一次,但是当你混合时,每个像素至少要绘制2次。因为我们要知道alpha透明混合视图内部是什么,才能进行混合。在某些情况下,单一的alpha透明混合视图会造成你的视图层级内一个完整分支被绘制2次。潜在性能问题,因为,硬件层有很多前端代价,但随着时间推移会变得廉价。第一次使用硬件层时,它可比直接绘制到屏幕上花费的多。

节省的部分在后面,当你重复使用层而不更换内容时。但是,android系统默认在每一帧之后,渲染器丢弃硬件层。所以,要实现优化,就要显式的提醒系统,重复使用硬件层。

优化:

1.重复使用硬件层。android 16以上直接使用中间的语句,让动画来自动管理层类型。16以下的使用前一句和最后一句。



2.明确功能,根据业务重写View.hasOverlappingRendering。

22.使用android studio中的Lint工具检查静态代码的优化问题。可能检查的事项比较多,那么有一些简单建议:

1.确保你在绘制代码中设置了内存配置(Memory allocations within drawing code),抛出一个错误。

2.将overdraw检测纳入警告类。

23.LRU Cache:

根据应用可用的内存总量来设置cache大小:



getMemoryClass指出为了让系统最佳工作,你的应用本身应该设置的内存限制。

24.关于迭代器:在java中,为了稳定性和可维护性,都要求使用迭代器来遍历数组或其他数据结构。但是这也是有性能损失的。如果在非常重性能的情况下,应该慎重考虑。

试验:对ArrayList和Vector进行三种语法的试验(for,标准iterator,简化iterator(for(Item item:list)))。结果如下:



注意:在替换前,看是否性能能够得到明显提升,这是用稳定性和可维护性来换取性能的例子。

25.关于object pool,网上有很多争议,其实现方法也比较困难。务必搞清楚在具体应用中是否值得用。

参考:

https://www.youtube.com/watch?v=bSOREVMEFnM&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=42

还有pocket中的文章。

26.network:



电流图:



请求:1.现在马上做(如用户主动下拉刷新)2.将来某个时间做(用JobScheduler)

针对now optimization:

1.好好利用预载取功能(prefetch)。本质上,试图预测用户在接下来5到10分钟可能需要的东西,或者1-5M的数据,提前获取那个内容。这样可以摆脱将来那些独立微小的请求的负担。

2.确保要对你可以控制的上传或下载的任何内容进行高度压缩。总的来说,需要压缩或解压内容的CPU周期的电池性能,通常会大大低于无线电用于传送该负载至网络上成本。

监测工具:Networking Profiling(网络连接剖析)。

27.网络连接性能在于缩短用户请求数据到我们返回数据的时间。很多事物影响这个变量。比如带宽延时,蜂窝网连接速度。

原则:

1.减少无线电活跃时间

2.减少获取数据的大小

网络请求的分类:

1.用户要求你做的。(手动刷新)

2.服务器要对你进行的更新(传回一个response,有新的社交数据可用)

3.需要频繁上传的数据(上传分析,搜索任何设备位置)

后两个是优化的重点。

1.绝不应该定期轮询服务器获取更新!,这就是浪费带宽和电量,让服务器告诉你什么都没有改变

解决办法:例如借助Google云端推送,会让服务器有新内容时提示应用。GCMNetworkManager是一个Google Play服务API,可以帮助你规划网络连接导向任务,并为你处理批处理。

28.关于压缩数据:

https://www.youtube.com/watch?v=Eb7rzMxHyOk&list=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H&feature=iv&src_vid=l5mE3Tpjejs&annotation_id=annotation_296967671

http://www.html5rocks.com/en/tutorials/speed/img-compression/

https://www.youtube.com/watch?v=whGwm0Lky2s&feature=iv&src_vid=l5mE3Tpjejs&annotation_id=annotation_1270272007

http://www.html5rocks.com/en/tutorials/speed/txt-compression/

仔细想你发送xml和json数据包的频率,可能发现不应该发送这些原始文本数据,相反应该用Protobufs或FlatBuffers格式进行杠杆作用

停止更新!!!看到胡凯同学的总结,比我自己写的好多了。弃坑!!!

传送地址:http://hukai.me/blog/archives/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息