Android 内存泄漏实战:从排查到修复的完整指南
通过实战示例和工具使用,帮助开发者理解、排查和修复 Android 应用中的内存泄漏问题
1. 什么是内存泄漏?
定义:内存泄漏是指程序中已动态分配的内存由于某种原因未能释放,导致系统内存的浪费,最终可能导致应用崩溃或性能下降。
在 Android 中的表现:Activity 或 Fragment 被销毁后,仍然被其他对象持有引用,导致无法被垃圾回收器回收
2. 内存泄漏的常见场景
以下是 Android 开发中常见的内存泄漏场景:
(1)静态变量持有 Context 引用
public class LeakExample {
private static Context sContext;
public static void setContext(Context context) {
sContext = context; // 静态变量持有 Activity 引用,导致内存泄漏
}
}
(2)非静态内部类持有外部类引用
public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 发送延迟消息
mHandler.sendEmptyMessageDelayed(0, 10000);
}
}
(3)未取消的注册监听器
public class MainActivity extends AppCompatActivity {
private SensorManager sensorManager;
private Sensor sensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 未取消注册监听器,导致内存泄漏
// sensorManager.unregisterListener(this);
}
}
(4)匿名内部类持有外部类引用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
// 长时间运行的任务
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
3. 内存泄漏的排查工具
(1)Android Profiler
使用 Memory Profiler 监控内存使用情况。
捕获堆转储(Heap Dump)并分析内存中的对象。
(2)LeakCanary
集成 LeakCanary 库,自动检测内存泄漏。
添加依赖:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}
初始化:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
LeakCanary.install(this);
}
}
4. 内存泄漏的修复方法
(1)避免静态变量持有 Context 引用
使用 WeakReference 或 Application Context。
public class LeakExample {
private static WeakReference<Context> sContextRef;
public static void setContext(Context context) {
sContextRef = new WeakReference<>(context);
}
}
(2)使用静态内部类 + WeakReference
将非静态内部类改为静态内部类,并使用 WeakReference 持有外部类引用。
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
private WeakReference<MainActivity> mActivityRef;
MyHandler(MainActivity activity) {
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivityRef.get();
if (activity != null) {
// 处理消息
}
}
}
private MyHandler mHandler = new MyHandler(this);
}
(3)及时取消注册监听器
在 onDestroy() 中取消注册监听器。
@Override
protected void onDestroy() {
super.onDestroy();
sensorManager.unregisterListener(this);
}
(4)避免匿名内部类持有外部类引用
将匿名内部类改为静态内部类,或使用 WeakReference。
public class MainActivity extends AppCompatActivity {
private static class MyRunnable implements Runnable {
private WeakReference<MainActivity> mActivityRef;
MyRunnable(MainActivity activity) {
mActivityRef = new WeakReference<>(activity);
}
@Override
public void run() {
MainActivity activity = mActivityRef.get();
if (activity != null) {
// 执行任务
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new MyRunnable(this)).start();
}
}
5. 实战示例:修复一个内存泄漏问题
场景描述
一个 Activity 中使用了 Handler 发送延迟消息,导致 Activity 无法被回收。
修复步骤
将 Handler 改为静态内部类。
使用 WeakReference 持有 Activity 引用。
在 onDestroy() 中移除所有消息。
修复代码
public class MainActivity extends AppCompatActivity {
private MyHandler mHandler = new MyHandler(this);
private static class MyHandler extends Handler {
private WeakReference<MainActivity> mActivityRef;
MyHandler(MainActivity activity) {
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivityRef.get();
if (activity != null) {
// 处理消息
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.sendEmptyMessageDelayed(0, 10000);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null); // 移除所有消息
}
}
6. 总结
内存泄漏是 Android 开发中的常见问题,可能导致应用崩溃或性能下降。
通过工具(如 Android Profiler 和 LeakCanary)可以快速定位内存泄漏。
使用 WeakReference、静态内部类、及时取消注册等方法可以有效修复内存泄漏。
通过本文的实战指南,你可以掌握 Android 内存泄漏的排查和修复技巧,提升应用的质量和性能。