Android 内存泄漏分析与解决
常见内存泄漏场景与解决方案
目录
内存泄漏基础
常见泄漏场景
LeakCanary 使用指南
静态变量导致的泄漏
非静态内部类与 Handler
资源未关闭
Compose 中的泄漏
1. 内存泄漏基础 什么是内存泄漏
flowchart TB
subgraph Normal["正常内存使用"]
N1["创建对象"] --> N2["使用"] --> N3["不再需要"] --> N4["GC 回收"]
end
subgraph Leak["内存泄漏"]
L1["创建对象"] --> L2["使用"] --> L3["不再需要"] --> L4["无法回收"]
L4 --> L5["原因:仍被引用"]
end
内存泄漏的影响
应用卡顿 : 垃圾回收频繁触发
OOM 崩溃 : 内存不足
电池消耗 : GC 占用 CPU
2. 常见泄漏场景
场景
原因
解决方案
静态 View
View 持有 Activity 引用
使用 WeakReference
Handler
延迟消息持有 Activity
移除消息/使用弱引用
非静态内部类
隐式持有外部类引用
改为静态类/弱引用
Thread
线程持有 Activity
使用 Lifecycle-aware 组件
监听器未移除
监听器持有对象引用
在 onDestroy 移除
Adapter 未清理
ViewHolder 持有 View
使用 ViewBinding
3. LeakCanary 使用指南 集成 LeakCanary 1 2 3 4 5 6 7 dependencies { debugImplementation "com.squareup.leakcanary:leakcanary-android:2.12" }
LeakCanary 工作原理
flowchart TD
LifeEnd["Activity / Fragment 生命周期结束"] --> Watch["监听对象是否被回收"]
Watch --> Check["5 秒后检查引用是否仍然存在"]
Check -->|可回收| NormalLeak["正常,忽略"]
Check -->|仍存在| Dump["Dump Heap,分析引用链"]
Dump --> Report["生成泄漏报告,显示引用链"]
典型泄漏报告解读
flowchart TB
Root["GC ROOT: MainThread (id=1)"] --> Activity["this$0 (MainActivity)<br/>外部类 this"]
Activity --> HandlerLeak["mHandler (Handler)"]
HandlerLeak --> Callback["mCallback (Runnable)"]
Callback --> Inner["this$0 (anonymous class)<br/>匿名内部类持有外部引用"]
Inner --> Issue["问题:Handler 延迟消息持有 Activity 引用"]
4. 静态变量导致的泄漏 问题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MainActivity : AppCompatActivity () { companion object { var instance: MainActivity? = null } override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) instance = this } override fun onDestroy () { super .onDestroy() instance = null } }
静态 View 泄漏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MainActivity : AppCompatActivity () { companion object { var textView: TextView? = null } override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) textView = findViewById(R.id.text_view) } }
解决方案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class MainActivity : AppCompatActivity () { companion object { var instance: WeakReference<MainActivity>? = null } override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) instance = WeakReference(this ) } override fun onDestroy () { super .onDestroy() instance?.clear() instance = null } }
5. 非静态内部类与 Handler Handler 泄漏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class MainActivity : AppCompatActivity () { private val handler = Handler(Looper.getMainLooper()) { println("Message processed" ) true } override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) handler.sendEmptyMessageDelayed(0 , 10000 ) } override fun onDestroy () { super .onDestroy() } }
解决方案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class MainActivity : AppCompatActivity () { private val handler = Handler(Looper.getMainLooper()) { println("Message processed" ) true } override fun onDestroy () { handler.removeCallbacksAndMessages(null ) super .onDestroy() } } class SafeHandler @Nullable constructor ( looper: Looper ) : Handler(looper) { private var mActivity: WeakReference<Activity>? = null fun setActivity (activity: Activity ) { mActivity = WeakReference(activity) } override fun handleMessage (msg: Message ) { val activity = mActivity?.get () if (activity != null && !activity.isFinishing) { } } }
内部类泄漏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class MainActivity : AppCompatActivity () { private class AsyncTask extends AsyncTask <Void, Void, String > { override fun doInBackground (Void ... voids) { return "" } override fun onPostExecute (String s) { } } private static class SafeAsyncTask extends AsyncTask <Void, Void, String > { private WeakReference<Activity> activityRef; SafeAsyncTask(Activity activity) { this .activityRef = new WeakReference<>(activity); } override fun onPostExecute (String s) { Activity activity = activityRef.get (); if (activity != null && !activity.isFinishing) { } } } }
6. 资源未关闭 常见未关闭资源
资源
后果
解决方案
Cursor
内存泄漏
close()
Stream
内存泄漏
use {}
Bitmap
OOM
recycle()
注册监听器
泄漏
unregister()
正确示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 fun getUsers () : List<User> { val db = database.readableDatabase val cursor = db.query("users" , null , null , null , null , null , null ) val users = mutableListOf<User>() while (cursor.moveToNext()) { users.add(cursor.toUser()) } return users } fun getUsers () : List<User> { val db = database.readableDatabase val cursor = db.query("users" , null , null , null , null , null , null ) return cursor.use { val users = mutableListOf<User>() while (cursor.moveToNext()) { users.add(cursor.toUser()) } users } }
文件流 1 2 3 4 5 6 7 8 9 10 11 12 fun readFile (path: String ) : String { val fis = FileInputStream(path) return fis.bufferedReader().readText() } fun readFile (path: String ) : String { return FileInputStream(path).use { fis -> fis.bufferedReader().readText() } }
7. Compose 中的泄漏 remember 生命周期问题 1 2 3 4 5 6 7 8 9 10 11 12 @Composable fun Screen () { var state by remember { mutableStateOf("" ) } val context = LocalContext.current val sharedPrefs = remember { context.getSharedPreferences("prefs" , Context.MODE_PRIVATE) } }
DisposableEffect 正确清理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Composable fun SensorScreen (context: Context ) { var rotation by remember { mutableFloatStateOf(0f ) } DisposableEffect(Unit ) { val sensorManager = context.getSystemService<SensorManager>() val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) val listener = object : SensorEventListener { override fun onSensorChanged (event: SensorEvent ?) { rotation = event?.values?.get (0 ) ?: 0f } } sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI) onDispose { sensorManager.unregisterListener(listener) } } }
避免重组泄漏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Composable fun BadExample () { var list by remember { mutableStateOf(listOf<String>()) } LaunchedEffect(Unit ) { someFlow.collect { data -> list = list + data } } } @Composable fun GoodExample () { var list by remember { mutableStateOf(listOf<String>()) } LaunchedEffect(Unit ) { someFlow.collect { data -> list = list + data } } }
内存分析工具
工具
用途
LeakCanary
自动检测 Activity/Fragment 泄漏
Android Profiler
实时内存监控
MAT (Memory Analyzer Tool)
深入分析堆内存
jmap/jhat
命令行内存分析
总结
flowchart TB
LeakChecklist["内存泄漏检查清单"] --> L1["静态变量使用 WeakReference"]
LeakChecklist --> L2["Handler 在 onDestroy 移除消息"]
LeakChecklist --> L3["内部类使用静态 + WeakReference"]
LeakChecklist --> L4["资源使用 use {} 自动关闭"]
LeakChecklist --> L5["监听器在 onDestroy 移除"]
LeakChecklist --> L6["使用 LeakCanary 检测"]
相关文章 :