Appearance
内存泄漏检测 - LeakCanary
字数统计:约 8000 字
难度等级:⭐⭐⭐⭐
面试重要度:⭐⭐⭐⭐⭐
目录
1. LeakCanary 简介
1.1 什么是 LeakCanary
LeakCanary 是 Square 开源的内存泄漏检测库:
- 自动检测 Activity、Fragment、View 泄漏
- 提供详细的引用链分析
- 实时通知
- 低性能开销1.2 工作原理
工作流程:
1. 监控对象生命周期
2. 等待 GC
3. 检查对象是否存活
4. 堆转储分析
5. 生成引用链报告2. 集成与配置
2.1 添加依赖
gradle
dependencies {
// Debug 版本启用
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
// 可选:不在通知栏显示
// debugImplementation 'com.squareup.leakcanary:leakcanary-android-no-hint:2.14'
}2.2 初始化
kotlin
// LeakCanary 2.x 自动初始化
// 无需手动配置
// 自定义配置(可选)
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 自定义配置
LeakCanary.config = LeakCanary.config.copy(
// 排除某些类
referenceMatchers = LeakCanary.config.referenceMatchers +
customMatchers()
)
}
}3. 使用指南
3.1 查看泄漏报告
泄漏通知流程:
1. 检测到泄漏
2. 通知栏显示
3. 点击查看详情
4. 分析引用链
5. 修复泄漏3.2 解读报告
泄漏报告内容:
- 泄漏对象
- 引用链
- 泄漏原因
- 修复建议
示例:
🔴 LEAK FOUND
泄漏对象:com.example.MainActivity @ 0x12345678
引用链:
java.lang.ref.WeakReference<com.example.MainActivity>
→ com.example.Singleton.instance
→ com.example.MainActivity @ 0x12345678
说明:Singleton 持有静态引用导致泄漏
建议:使用 WeakReference 或 Application Context4. 常见泄漏场景
4.1 静态集合
kotlin
// ❌ 错误
class BadCache {
companion object {
private val cache = mutableListOf<Any>() // 静态集合
}
}
// ✅ 正确
class GoodCache {
private val cache = LruCache<String, Any>(16)
}4.2 非静态内部类
kotlin
// ❌ 错误
class Outer {
inner class Inner {
// 持有外部类引用
}
}
// ✅ 正确
class Outer {
class StaticInner {
// 不持有外部类引用
}
}4.3 未注销监听器
kotlin
// ❌ 错误
class MyActivity : AppCompatActivity() {
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerReceiver(receiver, IntentFilter("ACTION"))
// 忘记注销
}
}
// ✅ 正确
class MyActivity : AppCompatActivity() {
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerReceiver(receiver, IntentFilter("ACTION"))
}
override fun onDestroy() {
unregisterReceiver(receiver)
super.onDestroy()
}
}4.4 线程泄漏
kotlin
// ❌ 错误
class MyActivity : AppCompatActivity() {
private val thread = Thread {
while (true) {
// 持有 Activity 引用
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
thread.start()
}
// 忘记停止线程
}
// ✅ 正确
class MyActivity : AppCompatActivity() {
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
scope.launch {
// 协程与生命周期关联
}
}
override fun onDestroy() {
scope.cancel()
super.onDestroy()
}
}5. 高级用法
5.1 手动监控
kotlin
class ManualWatching {
fun watchObject(obj: Any) {
if (BuildConfig.DEBUG) {
// 手动监控对象
// LeakCanary 内部 API
}
}
}5.2 排除假阳性
kotlin
// 某些情况可能误报
// 可以配置排除规则
class LeakCanaryConfig {
fun configure() {
LeakCanary.config = LeakCanary.config.copy(
// 排除已知假阳性
)
}
}6. 面试考点
6.1 基础概念
Q1: LeakCanary 的工作原理?
答案要点:
1. 监控对象生命周期
2. 等待 GC
3. 检查对象存活
4. 堆转储分析
5. 生成引用链Q2: 常见的内存泄漏场景?
答案要点:
1. 静态集合持有对象
2. 非静态内部类
3. 未注销监听器
4. 线程未停止
5. 单例持有 Context6.2 实战问题
Q3: 如何集成 LeakCanary?
gradle
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
// 自动初始化,无需配置Q4: 如何修复内存泄漏?
答案要点:
1. 查看 LeakCanary 报告
2. 分析引用链
3. 解除不必要的引用
4. 使用 WeakReference
5. 及时清理资源参考资料
本文完,感谢阅读!