1. 背景:Android App优化, 要怎么做?
2. Android App优化之性能分析工具
3. Android App优化之提升你的App启动速度之理论基础
4. Android App优化之提升你的App启动速度之实例挑战
5. Android App优化之Layout怎么摆
6. Android App优化之ANR详解
7. Android App优化之消除卡顿
8. Android App优化之内存优化
9. Android App优化之持久电量
10. Android App优化之如何高效网络请求
一般来说, 学习一门新的技术, 最应该做的就是阅读其官方文档, 那是最权威的。Android本身给我们提供了很多App性能测试和分析工具, 而且大部分都集成到Android Studio或DDMS中, 非常方便使用。
· 说明
顾名思义, "严格模式", 主要用来限制应用做一些不符合性能规范的事情. 一般用来检测主线程中的耗 时操作和阻塞. 开启StrictMode后, 如果线程中做一些诸如读写文件, 网络访问等操作, 将会在Log console输出一些警告, 警告信息包含Stack Trace来显示哪个地方出了问题.
· 文档
o https://developer.android.com/reference/android/os/StrictMode.html
· 作用
o 主要用来做主线程优化分析
· 说明
Systrace是一个收集和检测时间信息的工具,它能显示CPU和时间被消耗在哪儿了,每个进程和线程都在其CPU时间片内做了什么事儿.而且会指示哪个地方出了问题,以及给出Fix建议.
其以trace文件(html)的方式记录.可以直接用Chrome浏览器打开查看.界面如下:
· 文档
o https://developer.android.com/studio/profile/systrace.html
o https://developer.android.com/studio/profile/systrace-walkthru.html
o https://developer.android.com/studio/profile/systrace-commandline.html?hl=fy
· 作用
o 作用很多,个人主要用来分析UI的绘制时间,结合Hierarchy Viewer来提升UI性能.
o 也可以用来发现耗时操作.
· 说明
Hierarchy Viewer提供了一个可视化的界面来观测布局的层级,让我们可以优化布局层级,删除多余的不必要的View层级,提升布局速度.
有必要说明下的是:
上图红框标出的三个点是关键分析数据. 左起依次代表View的Measure, Layout和Draw的性能. 另外颜色表示该View的该项时间指数, 分为:
* 绿色, 表示该View的此项性能比该View Tree中超过50%的View都要快.
* 黄色, 表示该View的此项性能比该View Tree中超过50%的View都要慢.
* 红色, 表示该View的此项性能是View Tree中最慢的.
· 文档
o https://developer.android.com/studio/profile/hierarchy-viewer.html
o https://developer.android.com/studio/profile/hierarchy-viewer-walkthru.html
o https://developer.android.com/studio/profile/hierarchy-viewer-setup.html
o https://developer.android.com/studio/profile/optimize-ui.html#HierarchyViewer
· 作用
o 用来做View层级分析,可以分析出View Tree中的性能阻塞点,以便对症下药,提升布局性能.
Hierarchy Viewer需要Root的机器(产品机没有开启ViewServer)才可以执行。可以使用第三方的开源的ViewServer来协助我们在未Root的机器上使用Hierarchy Viewer分析.
· 文档
o https://developer.android.com/studio/profile/traceview.html
o https://developer.android.com/studio/profile/traceview-walkthru.html
· 作用
o 分析方法调用栈以及其执行时间,优化方法执行.
· 说明
内存使用检测器,可以实时检测当前Application的内存使用和释放等信息,并以图形化界面展示。
· 文档
o https://developer.android.com/studio/profile/am-memory.html
o https://developer.android.com/studio/profile/heap-viewer-walkthru.html
o https://developer.android.com/studio/profile/allocation-tracker-walkthru.html
· 作用
o 用来做内存分析,内存泄露排查的不二之选.可以结合heap viewer, allocation tracker来分析.
o 可以导出hprof文件结合第三方的MAT工具分析泄露点.
· 说明
Android Studio的Monitor还提供了其他三个Motinor --- CPU, GPU,Network.
· 文档
o https://developer.android.com/studio/profile/am-cpu.html
o https://developer.android.com/studio/profile/am-gpu.html
o https://developer.android.com/studio/profile/am-network.html
· 作用
o 分别用来跟踪监测CPU,GPU和Network的使用极其变化,可以作为网络优化,流量优化和渲染优化等的一个指导. (个人并不常用到~)
Android的开发者模式中也提供了较多的用来监测性能的选项, 可以用下:
以下工具全部开源
· 说明
Google出品, 通过Android系统的bug report文件来做电量使用分析的工具.
· 文档
o https://github.com/google/battery-historian
· 作用
o 用来做电量使用分析.
· 说明
针对Android App的CPU, 内存, 网络, 电量等多项综合的测试分析.
· 文档
o https://github.com/NetEase/Emmagee
· 作用
o 比官方工具更适合国人使用来做App的整体性能分析.
· 说明
Square出品, 必属精品.类似于App探针的内存泄露监测工具.
· 文档
o https://github.com/square/leakcanary
· 作用
o 集成到App中,用来做内存问题预防最好不过了.
· 说明
一个library, 用来检测Activity生命周期执行性能, Dagger2注入性能以及帧率性能的工具.
· 文档
o https://github.com/frogermcs/AndroidDevMetrics
· 作用
o 如果你的应用使用的Dagger2,这个就比较必要了.
(转自)Android Studio Memory Monitor
http://blog.csdn.net/flyworkspace/article/details/54019812
生成内存镜像,当从图中发现内存使用较高时,点击小卡车图标,可以主动触发GC。当应用内存使用很高,并且存在很严重的内存泄露时,点击该按钮后的效果并不明显,内存并没有降低或者降低的很少。点击"Dump Java Heap"图标稍等片刻,会生成该应用的内存快照。如图
• Total Count:内存中该类对象个数。
• Heap Count:堆内存中该类对象个数。
• Sizeof:每个对象的大小(如果为0,则大小不固定)。
• Shallow size:对象本身占有内存大小。
• Retained Size:释放该对象后,节省的内存大小。
其中,Retained Size之所以比Shallowsize大的原因是,该对象释放后,会引起其他对象的回收。 例如,某个对象被回收后: 该对象引用的其他对象也会被回收, 该对象A被另一对象B强引用后,之前对象B因为强引用该对象A而没有被回收,现在该对象A被回收后,若对象B强引用的其他对象都已被回收,则对象B也会被回收。
优化内存:
点击Class Name中的类名,查看其所有实例(Instance),分析实例中参数所占用的内存。根据Retaine Size排序,查找Instance中Depth较小的实例或者参数,在代码中找到相应的位置,查看内存占用是否合理。
判断内存泄露的步骤:
从Total Count入手。该类的对象数量不对。
• 很多对象只可能存在1个,若存在多个,则可能存在泄露。例如MainActivity的数量为2。又或者由于单例的使用不规范而导致创建多个“单例”对象。
• 某个对象已经不再使用,而其还在内存中显示。例如LoginActivity已经退出了,其数量为1。
Memory Monitor只提供了内存信息,如需详细信息,可以通过android studio的Captures(View—–Tool window—–Captures)栏,右键点击快照文件,Export to standard .hprof将堆快照(Heap Snapshot)转换成通用的hprof文件,之后可以通过其他内存分析工具打开,例如MAT。
点击“Start Allocation Tracking”开始监听内存的分配情况,再次点击,监听完成,生成报告。该报告显示这段时间内,内存的分配情况。
2.1是从内存的静态信息中分析,是某一个点的内存使用情况。2.2是跟踪某一段时间内内存的分配情况,是个过程跟踪。分析内存可以相结合,例如,再进行某个操作前,执行2.1导出静态内存信息,在开启2.2开始跟踪内存的分配。当执行完操作的时候,关闭内存分配的跟踪,再次执行2.1的,导出操作某个流程后的静态信息。将2.1的两个静态表结合2.2的内存分配动态过程一起分析。
打开某应用后,切换几个页面,内存飞速上涨。这只是一个极端例子,有很多app,随着用的时间越长,内存也是一直在升高。
根据2.1的方法,生成内存镜像。
查找可疑的对象,这个过程是逐个分析的过程,例如byte[]其实是其他对象的某个参数,很多本质上都是byte[],例如Bitmap中mBuffer也是byte[],当内存中有很多Bitmap的时候,byte[]也会很高。所以byte[]不是我们重点关注对象,如果真的是因为Bitmap(或者其他类)多而造成的byte[]高,那么下面肯定会有该类也会占用很高内存。
继续分析下一个HashMap$HashMapEntry。点击它后,在Instance栏中,看到其实例很多,先从占用大的实例入手。
例如99=这个,点击它后ReferenceTree显示如下:
得知这个HashMap是ReuseThumbnail…类中ReuseThumbnailManager的REUSE_BITMAPS。在代码中查看其大小是否合理。本例中REUSE_BITMAPS参数是static参数,其类型是HashMap,查看逻辑,看其是否正常。
再看其他参数,逐个分析其内存占用是否正常。
分析内存是个逐步的过程,一个问题解决后,再次循环这些步骤。有时候虽然列表中显示很多对象占用内存很高,有可能是同一个参数导致的,所以一个问题解决后,有可能有一系列参数占用高的情况会消失。就比如如果高内存bitmap的优化后,byte[]也很降低很多,其他参数也有可能会降低很多。
3.1是从静态内存信息中分析内存的使用,现在按照2.2从动态过程中跟踪内存的分配。
生成报告如下:
查看Size最大的一个Thread.
可以看到调用过程,从NewDisplayRunnale(执行了636次)调用了BitmapDecoder的decode方法(执行了135次),从代码中分析过程是否合理。
对于android的内存泄露,一般监测Activity的泄露居多,例如LeakCanary默认也是监测Activity是否泄露。
现写一个demo,故意造成内存泄露作为分析样例。
public class MyActivity extends Activity{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new TestThread().start();
}
class TestThread extends Thread{
@Override
public voidrun() {
super.run();
try{
Thread.sleep(10 * 60 * 1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
当进入MyActivity点击回退,重复多次。按照2.1方法获取内存镜像。
看到MyActivity的实例数量为17个。在右边的Analyzer Tasks栏中:
一般引起Activity泄露是由于其Context被强引用导致的。
MyActivity的context参数被TestThread引用了。所以在activity的销毁的时候,由于TestThread还引用着MyActivity,所以阻止了MyActivity被释放,因而导致内存泄露。
Android Studio中怎么使用DDMS工具?
http://www.cnblogs.com/gaobig/p/5029381.html
Android Studio开发工具中,打开DDMS,具体的方式如图:
打开之后的窗口如图:
查看内存信息:
Android学习之Android studio TraceView和lint工具的使用详解
http://blog.csdn.net/qq_16131393/article/details/51172488
打开AndroidDevice Monitor,这个大家都知道:
1. 选择你要调试的进程。
2. 点击start mothod profiling,待图标变黑。
3. 选择sample base profiling
这里需要解释一下:
Trace base profiling
整体监听,项目中所有方法都会监听,资源消耗比较大。
sample base profiling
抽样监听,以指定的频率进行抽样调查,一般不要超过5s,需要较长时间获取准确的样本数据。
再次点击start mothod profiling,就会生成检测样本。
效果如下:
上部分为时间轴,x轴表示时间,黑色区域可放大,每个区域代表每个方法的执行时间。y轴表示每一个独立线程。
下部分Name为你所选择的颜色区块所代表的性能分析。不同的颜色,代表不同的方法,颜色长度代表占用时间。
属性介绍:
Incl cpu time:某方法占用cpu时间(父+子)
Excl cpu time:某方法本身占用cpu时间(父)
Incl Real time:某方法真正执行时间(父+子)
Excl Real time:某方法自身执行时间(父)
当然还有相应所占百分比,不过多介绍。
还有Calls+RecurCall调用次数+递归调用次数
还有比较重要的:
cpu time/call:平均每次调用占用cpu时间。
real time/call:平均每次调用所执行的时间。
我觉得这个参数很具有参考性。
打开每个方法,会显示Paents和children(即父方法和子方法),以及分别所占用时间。
· 说明
一个图形化的工具,用来展示和分析方法的执行时间.
按上图的标记顺序按下,我们就能看到内存的具体数据,右边面板中数值会在每次GC时发生改变,包括App自动触发或者你来手动触发。
下面是每一个对象都有的列名含义:
当我们点击某一行时,可以看到如下的柱状图:
横坐标是对象的内存大小,这些值随着不同对象是不同的,纵坐标是在某个内存大小上的对象的数量。
我们说HeapViewer适合发现内存泄漏的问题,那你知道何为内存泄漏么?
内存泄漏
英文名:Memory Leaks
标准解释:无用的单纯,但是还是没GC ROOT引用的内存
通俗解释:该死不死的内存
检测
那么如何检测呢?Heap Viewer中的数值会自动在每次发生GC时会自动更新,那么我们是等着他自己GC么?小弟不才,刚开始我就是这么一直等啊等,由于GC的时机是系统把握的,所以很不好把握,既然我们是来看内存泄漏,那么我们在需要检测内存泄漏的用例执行过后,手动GC下,然后观察data object一栏的total size(也可以观察HeapSize/Allocated内存的情况),看看内存是不是会回到一个稳定值,多次操作后,只要内存是稳定在某个值,那么说明没有内存溢出的,如果发现内存在每次GC后,都在增长,不管是慢增长还是快速增长,都说明有内存泄漏的可能性。
实例
先来看3个图:
1.刚打开首页,手动GC一下:
2.首页到详情页10遍,最后回到首页,手动GC一下,直到数值不再变化:
3.首页到详情页10遍,最后回到首页,手动GC一下:
1、Emmagee是网易杭州研究院QA团队开发的一个简单易上手的Android性能监测小工具,主要用于监控单个App的CPU,内存,流量,启动耗时,电量,电流等性能状态的变化,且用户可自定义配置监控的频率以及性能的实时显示,并最终生成一份性能统计文件。
2、操作完成后,从系统任务列表中选择Emmagee,并停止测试,在”storage\sdcard0”下找到命名类似”Emmagee_TestResult_20140403210532.csv”的文件,打卡即为监控的得到的数据。
3、将csv数据拷贝到excel中生成图表,即可清晰看到整个操作过程中cpu、内存等关键数据的变化。
Android性能测试小工具Emmagee - 敌测漏师
http://blog.csdn.net/anlegor/article/details/22895993
APP性能测试工具Emmagee的使用总结
http://blog.csdn.net/chenrushui/article/details/51589995
Android性能测试工具Emmagee
http://www.cnblogs.com/jytian/p/6516170.html
· 说明
Square出品, 必属精品,类似于App探针的内存泄露监测工具.
· 文档
o https://github.com/square/leakcanary
· 作用
o 集成到App中,用来做内存问题预防最好不过了.
LeakCanary使用指南(1)
http://blog.csdn.net/hmh0512/article/details/57053265?utm_source=tuicool&utm_medium=referral
快速集成
第一步:在build.gradle中添加如下依赖:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
第二步:在自己的Application(假设名为ExampleApplication)中添加如下代码:
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
}
}
到这里其实可以检测到Activity的内存泄露了,原理后面再说。以Debug模式运行你的App,你可以看到,你App的图标后面跟着一个Leaks图标,如下图;而如果你以Release模式运行,则没有这个图标。
测试使用
假装你是测试人员,你开始各种点击App,进行测试。然后你有幸看到这样一个弹框,如下图。
你很好奇,然后点击了弹框中间那个图标,于是手机屏幕的左上角出现了你App的图标,再下拉点击那个图标,或者从桌面上LeakCanary图标(跟在你App的图标屁股后面那个)点进去,你看到下图。点击+号可以展开,点击-号收起。
内存泄露往往发生在,生命周期较长的对象,直接或间接持有了生命周期较短的对象的强引用,导致了生命周期较短的对象不能及时释放。
上图已经够傻瓜式了,第一行表示生命周期较长的那个对象,图中是AliPayModel这个类;第二行表示生命周期长的那个持有了一个什么样的引用,图中是mActivity;第三行表示生命周期较短的那个对象,图中是SelectPayTypeActivity。
回去查看源码,发现AliPayModel是个单例,在SelectPayTypeActivity中以AliPayModel.getInstance(this).XXX()的方式调用单例中的XXX()方法。于是AliPayModel通过mActivity持有了SelectPayTypeActivity.this的引用。SelectPayTypeActivity本来应该在用户退出这个页面和进入其他Activity(尤其是其他Activity层级较深时)时释放掉,但是单例的生命周期贯穿整个App,AliPayModel一直引用着SelectPayTypeActivity,导致SelectPayTypeActivity不能及时释放,引发内存泄露。
public class AliPayModel extends BasePayModel {
private Activity mActivity;
private AliPayModel() {}
private static AliPayModel instance = new AliPayModel();
public static AliPayModel getInstance(Activity tag) {
instance.mActivity = tag;
return instance;
}
}
找到了原因,解决方法也呼之欲出。要么AliPayModel这个业务类不要定义成单例,要么mActivity由强引用改成软引用或者弱引用。Java的强、软、弱、虚四种引用的区别不在本文的讨论范围。
发现开源组件中的内存泄露
用上述方法,可以检测出各种各样的内存泄露,包括:WebView导致的内存泄露、资源未关闭导致的内存泄露、非静态匿名内部类导致的内存泄露、Handler导致的内存泄露等等。
请看下图,每次选择图片、上传头像时都会引发0.96M的内存泄露!
再按图索骥,发现罪魁祸首是将一个Activity定义为static。表示不是很能理解这种神代码。最让人心中万马奔腾的是,它竟然有2600多个star!在这个项目的Issues中很多人反映内存占用大、容易OOM、卡顿等,但是没有人从技术层面去查找和分析原因,更遑论去阅读源码,都是直接拿来就用!
Android App优化之性能分析工具
http://www.jianshu.com/p/da2a4bfcba68
Android开发调试必备-使用DDMS
http://blog.csdn.net/stzy00/article/details/46554529
Android内存分析工具(二):DDMS
http://blog.csdn.net/berber78/article/details/47784007
Android性能专项测试之Heap Viewer工具
http://blog.csdn.net/itfootball/article/details/48734553
正确使用Android性能分析工具——TraceView
http://android.jobbole.com/78995/
Android性能专项测试之MemoryMonitor工具
http://blog.csdn.net/itfootball/article/details/48712595
Android性能优化第(二)篇---Memory Monitor检测内存泄露
http://www.cnblogs.com/ldq2016/p/6628311.html
Android内存与性能
http://blog.kamidox.com/android-memory-guide.html
Android系统性能调优工具介绍
http://blog.csdn.net/innost/article/details/9008691/
Android开发——Android多进程以及使用场景介绍
http://blog.csdn.net/seu_calvin/article/details/53932171
理解Android进程创建流程
http://gityuan.com/2016/03/26/app-process-create/
LeakCanary使用指南(1)
http://blog.csdn.net/hmh0512/article/details/57053265?utm_source=tuicool&utm_medium=referral
利用LeakCanary来检查Android内存泄漏
http://www.jianshu.com/p/0049e9b344b0
LeakCanary中文使用说明
https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/