Android性能优化---内存优化

读书笔记:Android应用性能优化最佳实践

一、影响卡顿的基本原因

1.绘制任务太重
2.主线程任务耗时太长

二、页面绘制的流程

CPU准备数据---GPU从缓存列表获取数据----Display显示数据

三、性能优化检测工具

1.Profile GPU rendering :GPU呈现模式分析

或是使用dumpsys命令更直观的查看绘制的耗时
adb shell dumpsys gfxinfo com.efrobot.robot.video

2.Systrace UI
分析UI的性能
参考Systrace
3.TraceView
分析函数的执行过程和耗时时间
参考TraceView
4.Hierarchy Viewer
查看Layout的嵌套以及绘制的时间
5.Java Heap
查看内存分配
6.Allocation Trace
观察一段时间内,内存分配的次数和类
7.Show GPU Overdraw
手机检查过渡绘制

四、布局优化

1.减少层级
合理的使用布局

RelativeLayout:绘制层级少,可以替代LinearLayout多嵌套才能实现的效果,但是性能差,因为要横向,纵向测量两次。
LinearLayout:测量少,但是实现复杂布局需要多次嵌套。

使用Merge标签减少布局,优化布局层级

1.在Activity整体的布局中,跟布局元素要是FrameLayout
2.必须为该布局指定一个ViewGroup,并且attachToRoot为true
3.不能在ViewStub中使用

使用ViewStub提高显示速度:当布局在加载时不是所有所有元素都要显示时,可以使用

ViewStub只能加载布局
加载一次后就不能再对布局做操作

避免默认主题的背景:使用activity的自动主题时会有一个默认背景,由DecorView持有

this.getWindow().setBackground(null)

五、启动耗时优化

1.获取activity的启动时间
使用ADB命令

adb shell am start -W [packageName]/packageName.ActivityName

2.代码打点

Application,Activity声明周期打点
数据库操作打点
其他的耗时业务打点
3.优化的方向
1.UI布局:检查是否过渡绘制,布局嵌套,掉帧严重
2.逻辑优化:异步加载,延期加载,分布加载
3.避免后台线程操作造成频繁的GC:例如在ListView滑动时禁止使用后台线程下载图片
4.使用TraceView查看updateDisplayListIfDirty方法,最后画面刷新到屏幕上需要调用DisplayList方法

六、动画优化

1.使用属性动画优化刷新率,尽量避免补间动画
2.在动画上使用硬件加速(慎重使用 )

七、内存优化

GC的过程中,任何工作线程都将停止,GC的时间越长,卡顿越明显,还会造成OOM问题。
1.对象的几个阶段:创建---使用---不可达---不可见--不可达---收集---回收
不可见:无法找到引用该对象的引用关系,但可能被静态变量,JNI层强引用,无法回收

2.内存分配
ART和Dalvik虚拟机在内存分配
LinearAlloc:存储虚拟机中的类以及永久数据,一块只读的空间
Zygote Space:
Allocation Space:分配内存区域
Image Space:负责分配预加载类
Large Space:负责分配大对象地址

3.内存回收机制
年轻区---老年区--持久区

新生对象首先在eden区创建,当eden区满时,会将存活的内存放到s0区,s0区满时,会将此时还活着的对象移动到s1区域s0清零,当s1区域也满时,会复制s1中的数据到s0,反复执行几次后仍然活着的对象会放到老年代。在老年代经理过几次gc仍然存活的对象会被移动到 持久区中。

4.使用Allocation Tracker查看内存分配
Allocation Tracker可以查看一段时间内内存分配的次数,和分配的大小,详见参考文章
https://blog.csdn.net/itfootball/article/details/48735041
https://blog.csdn.net/itfootball/article/details/48750849

5.分析Hprof文件
通过AndroidStudio生成Hprof文件,观察视图,使用Merge Shortest Path to GC roots,查看合并节点后,是否还有可达到该对象的路径,如果有那么表示该对象无法回收,可能出现内存泄漏

八、引用区分

1.强引用:不会被GC回收,回收不了会OOM
2.软引用:在虚拟机报告内存溢出前,如果内存不足回收对象
3.弱引用:GC就回收

九、内存优化

1.在1000数量级以内使用ArrayMap
2.使用基本类型加@IntDef和@StringDef类代替枚举
3.使用LruCache管理图片
4.图片内存优化

在android上加载图片,需要将图片加载成位图(由多个像素点组成的图),再解锁成位图后,内存=宽x高x单位内像素。图片被处理32bit/像素的位图(ARGB_8888),红,绿,蓝,透明各占8bit。即使图片不存在透明区也会分配8bit的透明区。

5.可以修改图片的格式
RGB_565(16bit),ARGB_4444(16bit),ALPHA_8(8bit)。小屏手机且对图像要求不高可以使用rgb,圆角头像可以使用ARGB4444,.

BitmapFactory.Options option =new BitmapFactory.Options()
options.inPreferredConfig=Bitmap.Config.RGB_565
BitmapFactory.decodeStream(is,null,options)

6.inSampleSize,inDensity,inTargetDensity:
如果图片在内存中的大小远远大于使用大小可以使用inSampleSize来压缩图片,inScaled 会按照现有密度重新划分目标密度,重新计算图片大小.

使用inSampleSize压缩图片,
BitmapFactory.Options option =new BitmapFactory.Options()
option.inJustDecodeBounds=true;
BitmapFactory.decodeStream(is,null,options)
options.inScaled=true;
options.inDensity=options.outWidth;0
options.inSampleSize=40
options.inTargetDensity=dstWidth*options.inSampleSize;
options.inJustDecode=false;

6.使用三级缓存对大量图片进行优化

内存--本地--网络

1.使用LruCache
将最近使用过对象的强引用放到LinkedHashMap中,将最近最少使用的对象移除。
2.内存复用
使用Bitmap的options对象的inBitmap参数:在LruCache移除图片后,可以将移除的图片加入到复用集合中,当需要加载新的图片时,先查找内存,再查找复用集合中是否有符合的图片。

Bitmap inBitmap=cache.getBitmapFromReusableSet()
if(inBitmap!=null){
  options.inBitmap=inBitmap;
}

3.使用磁盘缓存
使用DiskLruCache

十、String的优化

参考:http://www.androidchina.net/5940.html
String的值是存储在常量池(在编译时期将值保存在.class文件中)中的,一旦创建将不可以修改。

十一、存储优化

1.SharePreference优化
Editor的commit是同步写入,apply是异步写入。在不需要返回值的情况下,使用apply能够极大的提升性能
SharePreference的的put和getEditor()会锁定Editor对象,所以大量写入SharePreference对象最后提前获得一个Editor对象,并且通过标志位判断是否需要读写。

if(开关没有改变&&没有发生变化){
}

2.数据库优化
1.使用SQLiteStatement来执行插入操作

SQLiteStatement statement=getSqliteDB().compileStatement(STR_INSERT_STATEMENT_CONTACTS);
statement.clearBindings();
statement.bind..();

2.更好的方法是使用事物
在数据库插入代码中,如果没有显示的使用事物,系统会自动创建一个事物,如果插入的频繁就会频繁的创建事物。所以显示的创建一次事物,可以提高效率。

getSqliteDB().beginTranscation();
for(){
   getSqliteDB().insert(...)
}
getSqliteDB().setTranscationSuccessful();
getSqliteDB().endTranscation();

十二、Service的包活

1.守护进程
2.网络连接保持和Service的交互
3.使用SyncAdapter:是一个系统服务,通过系统的定时器更新数据到ContentProvider,工作在一个独立的进程,属于核心进程级别。使用它本身也会提高进程级别

十三、耗电优化

1.android5.0提供了Battery Historian查看电量使用
2.使用命令

//获取电量权限,并重置电量日志
adb shell dumpsys batterystats --enable full-wake-history
shell dumpsys batterystats --reset
//保存数据
adb bugreport >bugreport.txt

将文件转化为html,需要下载battery-historian

python historian.py -a bugreport.txt >battery.html

3.注意消耗:使用WakeLock一定要记得释放
4.使用JobScheduler执行部分任务

重要不紧急的任务
耗电量较大的任务
可以批量执行的任务

十二、代码审查

1.单一职责,一个模块只负责一件事
2.对象的可扩展开放,可修改关闭
3.代码复用要提取一个公共类
4.是否有更好的实现
5.错误是否被更好的处理,而不是粗略屏蔽
6.效率:选用的算法是否更有效率

你可能感兴趣的:(Android性能优化---内存优化)