1.如何去优化自己现有的项目,运行更加流畅
单个app进程 会根据手机性能分配不同的内容如: 8m 16m 32m 64m
2.当然最好的是在开发项目是就避免内存泄漏
在android应用层开发的时候,主要还是对java层的内存进行分析
( 而c 和c++,是自己去分配内存和释放内存 -- 手动管理 malloc free)
3.内存泄漏:内存不在掌控之内,当一个对象已经不需要使用了,本该回收时,而有另一个正在使用的对象持有它的引用,从而导致对象不能被回收而停留在堆内存中,这样就产生了内存泄漏。
4.java 中GC也会占用CPU性能而大量的分配内存和GC回收的话,就会造成GC抖动,一样会使应用变卡,所以,我们也一样要避免。
5.了解Java回收机制,对象不再有任何的引用的时候,才会被GC回收。
静态的:
在程序编译时就已经分配好,这块的内存在程序整个运行期间都一直存在
存放的是静态数据。全局的static数据和常量
栈式的
存放了编译器可知的各种基本数据类型,(boolean byte,char,short,int,float,long,double)对象的引用(reference引用指针),
在执行函数(方法)时,函数的一些内部变量
堆内存
存放的是对象实例,动态内存分配,java中直接依赖GC机制
StrongReference:
回收时机:从不回收,使用:对象一般保存,生命周期:JVM停止的时候才会终止
SoftReference :
回收时机:到内存不足的时候,使用:SoftReference
WeakReference:
回收时机:在垃圾回收的时候,使用:同软引用,生命周期:GC后终止
PhatomReference:
回收时机:在垃圾回收的时候,合ReferenceQueue来跟踪对象被垃圾回收期回收的活动;生命周期:GC后终止
开发时:为了防止内存溢出,处理一些比较占用内存大并且生命周期长的对象的时候,可以尽量使用软引用和弱引用。
1.使用Android Monitor:
可以看右边两个颜色块的说明:
Allocated :代表已被分配的
Free: 代表没有被使用的内存
在Memory 有个卡车的标志 Initiate GC,代表手动GC按钮,而一般检测一个activity是否有内存泄漏的时候,是先记录当前的内存分配情况,然后打开需要检测的activity,进行一系列操作后关闭后GC,再次记录对比之前记录的情况,如果内存大于之前的值,则代表有内存泄漏,分析代码。
Dump Java Heap
基本在点击这个按钮之前,我一般会先GC下,这样可以减少无用的对象,在点击这个按钮后,耐心等待一会,就会发现有生成一个hprof文件,由此记录对比分析。基本可以解决大部分的OOM。
Start Allocation Tracking
这个主要是对各个线程作分析,使用方法先点击一次然后进行想检测的操作,最后在点击一次结束,然后找到自己想检测的方法,可以查看对应的方法,分析内存情况。
当app退出的时候,这个进程里面所有的对象应该就都被回收了,尤其是很容易被泄露的(View,Activity)是否还内存当中。
可以让app退出以后,查看系统该进程里面的所有的View、Activity对象是否为0.
工具:使用AndroidStudio--AndroidMonitor--System Information--Memory Usage查看Objects里面的views和Activity的数量是否0.
2.MAT 使用Eclipse插件 Eclipse Memory Analyzer
首先在运行时,参照上面使用Android Monitor,找到点击Dump Java Heap生成的文件,可以点击右边的Captures,右键点击Export to standard .hprof 文件,然后使用 Eclipse Memory Analyzer工具点File选择 open Heap dump ,将对应的文件导入,选择 Leak Suspect Report ,自动检查这个dump堆可能泄露的地方,给出报告对象的存活和为什么他们还没有被垃圾回收器回收掉。
现在大概介绍下 Eclipse Memory Analyzer的几个模块
action模块下:
Histogram:柱状图,列举了每个class中对象的实例
Dominator Tree :支配树 列举了存活着的最大的对象
Top Consumers: 高级用户:圆形图打印最大的对象
Duplicate Classes:重复的类 检测由多个类装载器加载的类。
report 模块下:
Leak Suspect 泄漏怀疑 包含了可能泄漏的和系统的概况
Top Componments 顶部组件:组件的列表报告大于总堆的1%。
1.怀疑对象
1)步骤记录,首先打开记录的文件。然后下面任务栏中的Navigation中的点击histogram右键选择add to Compare Basket,记得将两个文件都添加都Compare Basket
切换到Compare Basket,就可以看到两个histogram,点击!就会出现Compared Tables ,这里就有两个对象个数的对比结果。然后具体对象的对比,还有就是Shallow Heap和对象占用内存的对比
2)MAT对比操作前后的hprof来定位内存泄漏,bar栏上找到Group by... 的一个按钮,上面有一个Group By package,输入自己的包名,这样就可以找到自己写的代码的对象个数及堆栈大小。
2.MAT分析hprof来定位内存泄漏原因所在。
1)Dump出内存泄漏当时的内存镜像hprof,分析怀疑的类
2)把上面得出的这些对象逐一排查,
(1)进入histogram,过滤出某一个嫌疑对象的类
(2)然后分析持有改类对象引用的外部对象(在该类上面点击List Object--->with incoming references )
(3)过滤其他引用 (在类上面点击右键Merge Shortest Paths to GC Roots--->exclude all phantom/weak/soft etc.references)
(4)逐个分析每个对象的GC路径是否正常,此时就要进入代码分析此时这个对象的引用持有是否合理。
总结,容易出现内存泄漏几种情况
单例传入Context
接口监听 getViewTreeObserver
InputMethodManager
多线程
停止动画
Handler
性能优化的工具:
Android monitor
Allaction Tracking: 追踪内存分配信息。可以很直观的看到某个操作的内存是如何进行分配
打开Android Device Monitor 找到Allaction Tracking ,点击StartTracking ,执行手机操作,点击GetAllocation
当然这个不打开Android Device Monitor使用android Monitor也是可以的,Android Monitor则是点击开始和结束,会自动生成一个.alloc文件。在左上角有点击group by Methon &allocator 在后面又有一个块状的圆形图就可以一个内存分配情况,当然也可以切换为柱状图,点击自己想要的块,然后就可以选取我们想要检查的类
LeakCanary 直接可以在手机端查看内存泄露的工具
具体使用方法就不在此做详细介绍了,在https://github.com/square/leakcanary 有比较详细的介绍,使用也十分的简单,只要在代码中做好那些配置,可以关注下运行demo的app,自动会生成一个leaks的程序,在测试时,会自动收集程序中的内存泄露。并且记录。记录的都是对象对应的引用位置,可以具体查看代码中的引用位置做分析
下面看一下LeakCanary的执行
我们是在Application install方法
会调用LeakCanary 中的 androidWatcher()方法然后进行如下的调用。
RefWatcher
new AndroidWatcherExecutor() --->dumpHeap()/analyze()(--->runAnalysis())--->Hprof文件分析
new AndroidHeapDumper()
new ServiceHeapDumpListener()
3.Lint分析工具
Inspect code 代码检测
检测资源文件是否有没有用到的资源。
检测常见内存泄露
安全问题SDK版本安全问题
是否有费的代码没有用到
代码的规范---甚至驼峰命名法也会检测
自动生成的罗列出来
没用的导包
可能的bug
这部分中具体的就不做介绍了,直接翻译英文就基本可以理解
Specify Dependencies
在打开当前的类比如MainActivity,在选择的时候,可以直接选的对应的类
查看当前的类中写的引用
注:
Shallow Size
对象自身占用的内存大小,不包括它引用的对象。
针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。
Retained Size
当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)
换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。