android性能优化

工具

LeakCanary ,https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' 稳定版,兼容6.0

BlockCanary:https://github.com/markzhai/AndroidPerformanceMonitor
compile 'com.github.markzhai:blockcanary-android:1.5.0'

重点:systrace + 函数插桩

Memory Analysis Tool(MAT),

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

内存检查:

https://www.cnblogs.com/yezhennan/p/5442557.html
内存耗用名词解析:
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS

OOM:

内存泄露可以引发很多的问题:
1.程序卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC)
2.莫名消失(当你的程序所占内存越大,它在后台的时候就越可能被干掉。反之内存占用越小,在后台存在的时间就越长)
3.直接崩溃(OutOfMemoryError)

ANDROID内存面临的问题:

1.有限的堆内存,原始只有16M
2.内存大小消耗等根据设备,操作系统等级,屏幕尺寸的不同而不同
3.程序不能直接控制
4.支持后台多任务处理(multitasking)
5.运行在虚拟机之上

5R:

本文主要通过如下的5R方法来对ANDROID内存进行优化:
1.Reckon(计算)
首先需要知道你的app所消耗内存的情况,知己知彼才能百战不殆

2.Reduce(减少)
消耗更少的资源

3.Reuse(重用)
当第一次使用完以后,尽量给其他的使用

4.Review(检查)
回顾检查你的程序,看看设计或代码有什么不合理的地方。

5.Recycle(回收)
返回资源给生产流

下面从系统内存(system ram)和堆内存(heap)两个方面介绍一些查看和计算内存使用情况的方法:

1.系统内存:
procstats,meminfo他们一个侧重于后台的内存使用,另一个是运行时的内存使用。
procstats
2.Android 4.4 KitKat 提出了一个新系统服务,叫做procstats。它将帮助你更好的理解你app在后台(background)时的内存使用情况。
可以通过adb shell命令去使用procstats(adb shell dumpsys procstats --hours 3),
或者更方便的方式是运行Process Stats开发者工具(在4.4版本的手机中点击Settings > Developer options > Process Stats)

3.meminfo
Android还提供了一个工具叫做meminfo。它是根据PSS标准 (Proportional Set Size——实际物理内存)计算每个进程的内存使用并且按照重要程度排序。
你可以通过命令行去执行它:(adb shell dumpsys meminfo)或者使用在设备上点击Settings > Apps > Running(与Procstats不用,它也可以在老版本上运行)

命令查看内存等

1.查看Dalvik内存配置文件
adb pull /system/build.prop xxx 导入/system/build.prop到本地电脑

dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=192m
dalvik.vm.heapsize=512m
dalvik.vm.heapstartsize=8m 相当于虚拟机的 -Xms配置,该项用来设置堆内存的初始大小。
dalvik.vm.heapgrowthlimit=192m 相当于虚拟机的 -XX:HeapGrowthLimit配置,该项用来设置一个标准的应用的最大堆内存大小。一个标准的应用就是没有使用android:largeHeap的应用。
dalvik.vm.heapsize=512m 相当于虚拟机的 -Xmx配置,该项设置了使用android:largeHeap的应用的最大堆内存大小。

2.shell查看
adb shell getprop|grep dalvik.vm.heapstartsize 应用启动后分配的初始内存(某机型无效)
adb shell getprop|grep heapgrowthlimit 单个标准应用程序最大内存限制(没设置android:largeHeap)
adb shell getprop|grep dalvik.vm.heapsize 单个dalvik虚拟机最大的内存限制(设置了android:largeHeap)

Heap(堆内存):
在程序中可以使用如下的方法去查询内存使用情况

ActivityManager#getMemoryClass()

ActivityManager#getMemoryInfo(ActivityManager.MemoryInfo)
得到的MemoryInfo中可以查看如下Field的属性:
availMem:表示系统剩余内存
lowMemory:它是boolean值,表示系统是否处于低内存运行
hreshold:它表示当系统剩余内存低于好多时就看成低内存运行

android.os.Debug#getMemoryInfo(Debug.MemoryInfo memoryInfo)

dalvikPrivateDirty: The private dirty pages used by dalvik。
dalvikPss :The proportional set size for dalvik.
dalvikSharedDirty :The shared dirty pages used by dalvik.
nativePrivateDirty :The private dirty pages used by the native heap.
nativePss :The proportional set size for the native heap.
nativeSharedDirty :The shared dirty pages used by the native heap.
otherPrivateDirty :The private dirty pages used by everything else.
otherPss :The proportional set size for everything else.
otherSharedDirty :The shared dirty pages used by everything else.

说明:

dalvik:是指dalvik所使用的内存。
native:是被native堆使用的内存。应该指使用C\C++在堆上分配的内存。
other:是指除dalvik和native使用的内存。但是具体是指什么呢?至少包括在C\C++分配的非堆内存,比如分配在栈上的内存。
private:是指私有的。非共享的。
share:是指共享的内存。
PSS:实际使用的物理内存(比例分配共享库占用的内存)
PrivateDirty:它是指非共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使你的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。
SharedDirty:参照PrivateDirty我认为它应该是指共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使所有共享它的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。

android.os.Debug#getNativeHeapSize()
返回的是当前进程navtive堆本身总的内存大小
android.os.Debug#getNativeHeapAllocatedSize()
返回的是当前进程navtive堆中已使用的内存大小
android.os.Debug#getNativeHeapFreeSize()
返回的是当前进程navtive堆中已经剩余的内存大小

技巧:android:largeHeap="true”(小心使用)

@@@@@@@@@@@@@@@@@@@@@@@@@@

需要特别注意优化的点

1.Bitmap:

Bitmap是内存消耗大户,绝大多数的OOM崩溃都是在操作Bitmap时产生的,下面来看看如何几个处理图片的方法:

bitmap缓存:
内存缓存(LruCache)
硬盘缓存(DiskLruCache)

根据需求去加载图片的大小。

例如在列表中仅用于预览时加载缩略图(thumbnails )。
只有当用户点击具体条目想看详细信息的时候,这时另启动一个fragment/activity/对话框等等,去显示整个图片

图片大小:
直接使用ImageView显示bitmap会占用较多资源,特别是图片较大的时候,可能导致崩溃。
使用BitmapFactory.Options设置inSampleSize, 这样做可以减少对系统资源的要求。
属性值inSampleSize表示缩略图大小为原始图片大小的几分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。

图片像素:
Android中图片有四种属性,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存 (默认)
RGB_565:每个像素占用2byte内存

Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。 所以在对图片效果不是特别高的情况下使用RGB_565(565没有透明度属性)

图片回收:

使用Bitmap过后,就需要及时的调用Bitmap.recycle()方法来释放Bitmap占用的内存空间,而不要等Android系统来进行释放。

捕获异常:
经过上面这些优化后还会存在报OOM的风险,所以下面需要一道最后的关卡——捕获OOM异常:

2.强引用>软引用>弱引用>虚引用

强引用(strong reference)
如:Object object=new Object(),object就是一个强引用了。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
软引用(SoftReference)
只有内存不够时才回收,常用于缓存;当内存达到一个阀值,GC就会去回收它;

弱引用(WeakReference)
弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

虚引用(PhantomReference)
"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

3.缩小变量范围

4.对常量使用static final修饰符

5.Context生命周期过长,

尽量避免static成员变量引用资源耗费过多的实例,
广播
handler
toast

6避免创建不必要的对象

7.线程控制

8.UI Review(视图检查):

Android对于视图中控件的布局渲染等会消耗很多的资源和内存,所以这部分也是我们需要注意的。

减少视图层级:
减少视图层级可以有效的减少内存消耗,因为视图是一个树形结构,每次刷新和渲染都会遍历一次。

hierarchyviewer:
想要减少视图层级首先就需要知道视图层级,所以下面介绍一个SDK中自带的一个非常好用的工具hierarchyviewer。
你可以在下面的地址找到它:your sdk path\sdk\tools

合理运用分屏,转屏等

在视图中加载你所需要的,而不是你所拥有。因为用户不可能同时看到所有东西。最典型的例子就是ListView中的滑动加载。

9.使用时再下载

====================恢复activity状态

getLastNonConfigurationInstance,在oncreate或onstart里实例化,获取onRetainNonConfigurationInstance中保存的实例

和onSaveInstanceState这个方法最大的好处是:
* 当Activity曾经通过某个资源得到一些图片或者信息,那么当再次恢复后,无需重新通过原始资源地址获取,可以快速的加载整个Activity状态信息。
* 当Activity包含有许多线程时,在变化后依然可以持有原有线程,无需通过重新创建进程恢复原有状态。
* 当Activity包含某些Connection Instance时,同样可以在整个变化过程中保持连接状态。
注意:只做配置更改的优化,依然要处理空指针的情况

下边是需要特别注意的几点:
1.使用有风险
onRetainNonConfigurationInstance()
* The function will be called between {@link #onStop} and* {@link #onDestroy}.

如何加快应用启动速度

1.如果是6.0及以上,才考虑用闪屏。闪屏会带来100ms的优化。
2.懒加载,针对不同客户的加载。注意:防止集中化,导致首页加载后不可操作。
3.算法优化,
4.线程优化,注意防止加锁,导致线程阻塞。一般用线程池管理线程。控制线程数,减少cpu调度,以及频繁切换工作线程。
pipeline机制,根据业务优先级定义业务初始化时机。为各个任务建立依赖,但是如果没配置好,会导致主线程一直等待。
注:参考框架:mmkernel、 alpha,
5.gc情况,debug结合allocation工具

Debug.startAllocCounting

6.启动时尽量不要做系统调用,会占有cpu资源

Android崩溃入手

1.哪个进程、哪个线程。是否主线程,是前台进程,后台进程,还是系统进程。
2.是Java异常,native异常,还是anr

关于性能的两张图。

以下图片引自:https://time.geekbang.org/column/article/70250#previewimg

android性能优化_第1张图片
fb492a5ede709bbacb59953c04d986fb.png

android性能优化_第2张图片
211405b9dcf1291e1e1bb1fbfb2a70fd.jpeg.png

你可能感兴趣的:(android性能优化)