type
status
date
slug
summary
tags
category
password
icon
郭霖大神相关帖子 《Android 最佳性能实践(一)——合理管理内存》 《Android 最佳性能实践(二)——分析内存的使用情况》 《Android 最佳性能实践(三)——高性能编码优化》 《Android 最佳性能实践(四)——布局优化技巧》 Android 性能优化 《Android 性能优化必知必会》
什么是内存泄露?
- 传统定义的内存泄露:申请的内存忘记释放了。
- Android (或 JVM)的内存泄露:短⽣命周期的对象被⻓⽣命周期的对象持有,从⽽导致短⽣命周期的对象不能被释放
垃圾回收机制
垃圾回收机制分为「引⽤计数法」和「可达性分析法」:
- 「引⽤计数法」 Python , Object-C , Swift ⽤⼀个计数器记录⼀个对象被引⽤的次数,如果引⽤的次数被减少到 0 那么说明这个对象是垃圾对象。 都是引⽤计数(引⽤计数有循环引⽤的问题)
- 「可达性分析法」 Java Jvm 通过⼀些 GC Roots 向下搜索,如果可以被 Gc Roots 引⽤到的对象,说明这个对象不是垃圾对象,反之这个对象就算互相引⽤了也是垃圾对象 那些对象会被作为 GC Roots 呢?
- 在线程栈中的局部变量,也就是正在被调⽤的⽅法,它⾥⾯的参数和局部变量
- 存活的线程对象
- JNI 的引⽤
- Class 对象,因为 Android 加载 Class 后不会卸载 Class
- 引⽤类型的静态变量
内存泄露的问题
内存泄漏并不会⻢上把程序搞挂掉。但是随着应⽤的使⽤,不能回收的垃圾对象会越来越多,就导致了可⽤的内存越来越少,到最后应⽤就有可能在任何位置抛出 OutOfMemoryError ,这种情况下,每次 OOM 错误堆栈都不同,就很难定位问题。
监控 Activity 和 Fragment 原理
通过注册
Application
和 Activity
上的⽣命周期回调来完成在 Activity
和 Fragment
销毁的时候开始观察。1.x 的 LeakCanary 只监控了 support 包和 API 26 以上的 Fragment 。
四⼤引⽤
- 强⼀点的引⽤ 强引⽤——不会被垃圾回收
- 弱⼀点的引⽤
- 弱引⽤(
WeakReference
)——可以通过 get() 获得引⽤对象,会被垃圾回收 - 软引⽤(
SoftReference
)——可以通过 get() 获得引⽤对象,内存不⾜会被垃圾回收 - 虚引⽤(
PhantomReference
)——不能通过 get() 获得引⽤对象,会被垃圾回收
在 Android 中,官方推荐使用 android.util.LruCache 来作为缓存,而不是使用软引用,软引用的效率比较低
弱引⽤在引⽤对象被垃圾回收之前,如果引用对象只被弱引用引用(那么这个对象一定会在垃圾回收时被回收),弱引用会将自己放⼊它关联的队列中。所以可以通过队列中是否有对应的引⽤来判断对象是否会被垃圾回收了。

⽅法 watch() 源码分析
原理:就是通过弱引⽤的⽅式来判断队列中是否有弱引⽤来判断对象是否被垃圾回收了。
首先生成一个引用队列,然后将怀疑的对象生成一个 key,通过 key 创建一个弱引用对象,当 GC 回收这个对象时,弱引用会把自己添加到引用队列,这样就可以通过引用队列中的 key,去排除怀疑对象,剩余的 key 就是 GC 无法回收的引起内存泄露的对象。
触发 GC 的正确姿势
通过 android.os.Debug.dumpHprofData() 来获取 hprof ⽂件
分析会在独⽴进程中进⾏, 1.x 内部使⽤ haha , 2.x 内部使⽤ shark 。
在 1.x 版本中,通过 haha 第三⽅库进⾏堆⽂件分析。
在 2.x 版本中,通过 shark 第三⽅库进⾏堆⽂件分析,内存占⽤⼤幅度减少,分析速度⼤幅度提⾼。
2.0 不需要主动初始化的原理
ContentProvider#onCreate
会在 Application#onCreate
之前先执⾏ ,在这个 onCreate
中就可以进⾏初始化了。 LeakCanary 2.0 利⽤了这个 原理,所以不需要我们⼿动进⾏初始化。- 作者:shuouyang
- 链接:https://notion-tree.vercel.app/article/3b7d083e-9c18-4770-b7f5-f5dd8fe830f2
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。