1、内存占用高导致的问题
- 1、内存泄漏导致OOM崩溃
- 2、界面卡顿,影响用户体验
- 3、高内存耗电,被系统及安全软件警告,容易被卸载或后台关闭
之所以要内存优化为了更好的适应JVM的GC机制,减少对程序的影响(减少卡顿)。
2、JVM 内存模型
Minor GC
使用标记-清除-复制算法,将Eden区和From Survivor区中存活下来的对象复制到 To Survivor区中,然后清空Eden区和From Survivor区,速度快。
Major GC
采用标记-清除-压缩算法,即,先标记无用的对象,然后将存活下来的对象移动,整理碎片,以腾出更大的连续空间。
如下图所示:
JVM.png3、GC原理及简介
采用是否根节点可访问判断是否需要回收对象,如下图所示
GC.png3.1标记清除复制算法
mark-copy.png3.2标记清除复制算法
mark-press.png4、GC Reason和Name
Reason
Concurrent----后台回收内存,不暂停用户线程
Alloc----当app要申请内存,而堆又快满了的时候,会阻塞用户线程
Explicit----调用Systemt.gc()等方法的时候触发,一般不建议使用
NativeAlloc----当native内存有压力的时候触发
Name
Concurrent mark sweep----全部对象的检测回收
Concurrent partial mark sweep----部分的检测回收
Concurrent sticky mark sweep----仅检测上次回收后创
建的对象,速度快,卡顿少,比较频繁
GC log 示例
04-06 09:41:48.541 5021-5045/com.husor.beibei I/art: Background partial concurrent mark sweep GC freed 22647(1359KB) AllocSpace objects, 5(969KB) LOS objects, 6% free, 53MB/57MB, paused 5.128ms total 68.744ms
5、如何进行内存优化
- 1、消除内存泄漏
- 2、使用高性能编程
- 3、降低程序运行的内存占用
6、常见内存泄漏和高内存占用原因
- 1、慎重使用static变量
- 2、长周期内部类、匿名内部类长时间持有外部类引用导致相关资源无法释放(Handler或者内部线程等)
- 3、BitMap导致内存溢出
- 4、数据库、文件流等没有关闭
- 5、监听器、广播注册后没有及时注销
- 6、Adapter没有使用convertView
- 7、字符串拼接尽量使用StringBuilder或者StringBuffer
- 8、避免内存抖动,例如不要在onDraw中创建对象。
- 9、界面不可见时,停止动画和相关线程
6.1、示例一:
sample1.png原因:
sBackground, 是一个静态的变量,但是我们发现,我们并没有显式的保存Contex的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用。这个引用链如下:Drawable->TextView->Context
解决办法:
第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长
第三、使用WeakReference代替强引用。比如WeakReference<Context> mContextRef; (已经不推荐)
6.1、示例二:
sample2.png原因:
Activity退出后,其实例并未被回收。因为OneThread作为非静态内部类还持有BasicActivity的实例。
解决方案:
1、OneThread改为静态内部类
2、如果OneThread需要Context实例,使用弱引用保存它。
3、如果有必要,在BasicActivity的OnDestroy里面关闭线程
7、内存分析工具
7、1 Android Monitor
util1.png** 优点:**
使用简单,直观显示当前app的内存变化
缺点:
无法具体定位内存问题,只能给出内存笼统的变化。
常用于分析内存变化趋势。
7、2 Allocation Tracker
util2.png1、选择进程,在合适的实际开始和结束追踪。
2、Studio会自动打开文件,里面展示这一段时间内内存的分配情况,可以分析自己的程序哪里内存占用比较高,是否有大量的相同类型的 Object 被分配和释放。如果有,则其可能引起性能问题。
7、3 MAT
步骤:
- 1生成mat文件
在android studio 生成dump文件,并转为标准dump。
如下图所示
- 2使用mat分析
- 以内部线程导致内存泄漏为例分析:
1、多次打开该demo,生成dump文件
2、打开MAT工具,选择“File”>>“open heap dump”,打开dump文件
3、打开后在,“Action”里的“Histogram”,然后搜索SecondActivity
-
3猜测分析原因
通过上面看到,存在11个SecondActivity的实例,有点诡异。
选择SecondActivity这一项,然后右键“Merge Shortest Paths to GC Roots ”>>"exclude all phantom/weak/soft etc references.."
7、4LeakCanary 检测内存泄漏
leakcanary.png直接可以通过通知栏看到内存泄露的地方
LeakCanary参考资料:
https://github.com/square/leakcanary
http://blog.csdn.net/watermusicyes/article/details/46333925
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
网友评论