第十二章 内存, 视图和电量优化
内存优化
- 垃圾回收机制 GC (Garbage Collection)
In java, garbage means unreferenced objects.
Garbage Collection is process of reclaiming the runtime unused memory automatically. In other words, it is a way to destroy the unused objects.
To do so, we were using free() function in C language and delete() in C++. But, in java it is performed automatically. So, java provides better memory management.
1959年由John McCarthy提出 (created Lisp),自动内存管理和回收机制, 垃圾回收器负责回收程序中已经不使用,但是仍然被各种对象占用的内存 - 缺点:会占用大量系统资源
Android平台自带垃圾回收机制
Young Generation [生命周期短的对象] [Eden + S0 + S1 : Minor GC], Old Generation [生命周期长的对象], Permanent Generation [存放静态信息]
Android系统每隔16ms发出VSYNC信号,出发对UI进行渲染,所以整个过程如果保证在16ms内就可以达到一个60FPS的流畅的画面;如果某一帧的操作超过了16ms就会让客户感觉到卡顿;UI渲染过程发生GC,导致某一帧绘制时间超过16ms。
-内存泄漏
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。 内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
内存检测工具
Memory Monitor 显示当前内存使用和GC情况,快速定位卡顿是否和GC有关,快速定位Crash是否和内存占用过高有关,定位潜在的内存泄漏问题,简单易用但不能准确定位
Allocation Tracker (内存抖动,定位代码中分配的对象的类型,大小,时间,线程,堆栈等信息;配合Heap Viewer一起定位内存泄漏问题;使用复杂)
Heap Viewer (屏幕翻转会重新加载activity,heap viewer时效性好,每次GC后收集一次信息)
LeakCanary (A memory leak detection library for Android and Java, 方便查找内存泄漏)
在dependencies中添加debugComplier和releaseComplier两项,在onCreate()方法中添加LeakCanary.install(this); 即可
常见的内存泄漏问题
单例造成的泄漏 (匿名类,静态类等)
避免内存泄漏的方法 (尽量不要让静态变量引用Activity, 使用WeakReference, 使用静态内部类来代替内部类, 静态内部类使用弱引用来引用外部类, 在声明周期结束的时候释放资源)
减少内存使用 (使用更轻量级的数据结构e.g. SpareArray代替HashMap, 避免在onDraw中创建对象, 对象池(Message.obtain()), LRUCache, Bitmap内存复用, 压缩(inSampleSize, inBitmap), StringBuilder)
60FPS及UI卡顿
V-Sync (双缓冲机制 back buffer, frame buffer) 刷新率: 硬件刷新频率 Refresh Rate 60Hz; 帧率: GPU一秒内绘制的帧数 Frame Rate
过度绘制 (一个像素绘制超过一次, 会影响UI性能)
追踪过度绘制 show GPU Overdraw //打开开发者选项点击选中即可
GPU Profiler (快速查看渲染时间, 对比16ms) 蓝色部分表示测量绘制时间,创建更新Display List的时间; 红色部分表示执行时间,调用OpenGL ES API, 数据发送给GPU;橙色部分表示处理时间,CPU调用GPU的绘制
避免卡顿及优化过度绘制
- 避免UI卡顿
避免onDraw中创建对象[-对象池]
减少View层级,避免在UI顶层使用Relative Layout
自定义控件控制绘制复杂度
- 优化过度绘制
降低View层级 ·LinearLayout vs. RelativeLayout ·Merge
不必要的背景 ·去掉窗口默认背景 ·去掉不必要的背景
ClipRect & QuickReject
ViewStub
.9图用作背景
getWindow().setBackgroundDrawable(null);
电量消耗简介
- 电量消耗 网络, WakeLock, 非即时的任务 [battery-historian 查询]
电量优化
- 网络优化
网络请求批量处理 少唤醒网络模块的情况下发送多的请求而省电
Wifi状态下比移动网络耗电少很多
预取数据,也可以集中网络请求,减少唤醒网络模块的次数
尽量减少轮询服务器 可以使用第三方推送服务
数据压缩,可以减少时间从而省电,即使客户端解压缩会消耗更多内存,但耗电量远小于网络请求 比如可以用其他图片格式代替JPG
WakeLock 慎用
AlarmManager.setInexact();
JobScheduler
References:
详细介绍Java垃圾回收机制
http://www.cnblogs.com/laoyangHJ/articles/java_gc.html
Garbage Collector:
http://www.javatpoint.com/Garbage-Collection
Understanding Java garbage collection:
http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/index.html
How garbage collection works: s
http://www.dynatrace.com/en/javabook/how-garbage-collection-works.html
LeakCanary:
https://github.com/square/leakcanary
battery-historian