Android内存泄漏优化
1. 什么是内存泄漏?
内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,导致系统内存的浪费。在Android中,内存泄漏最终可能导致OOM(Out Of Memory)异常。
2. 常见的内存泄漏场景
2.1 静态变量引用Activity
public class MainActivity extends Activity {
private static Context sContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this; // 错误的做法,可能导致内存泄漏
}
}2.2 Handler使用不当
public class MainActivity extends Activity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// 延迟执行的任务
}
}, 10000);
}
}2.3 注册监听器未注销
public class MainActivity extends Activity {
private LocationManager locationManager;
private LocationListener locationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
// 实现监听方法
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
locationManager.removeUpdates(locationListener); // 记得注销监听
}
}3. 内存泄漏检测工具
3.1 Android Studio Memory Profiler
- 实时监控应用内存使用情况
- 查看内存分配情况
- 捕获堆转储并分析
3.2 LeakCanary
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
}使用示例:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
// LeakCanary会自动检测Activity和Fragment的内存泄漏
}
}
}4. 最佳实践
4.1 正确使用Handler
public class MainActivity extends Activity {
private static class MyHandler extends Handler {
private final WeakReference<MainActivity> activityRef;
MyHandler(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = activityRef.get();
if (activity != null) {
// 处理消息
}
}
}
private final MyHandler mHandler = new MyHandler(this);
}4.2 使用生命周期感知组件
public class MyViewModel extends ViewModel {
private final MutableLiveData<String> data = new MutableLiveData<>();
public void loadData() {
// 异步加载数据
// ViewModel会在Activity销毁时自动清理
}
}4.3 避免内部类持有外部类引用
public class MainActivity extends Activity {
private static class MyRunnable implements Runnable {
private final WeakReference<MainActivity> activityRef;
MyRunnable(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void run() {
MainActivity activity = activityRef.get();
if (activity != null) {
// 执行任务
}
}
}
}5. 面试常见问题
Q1: 如何排查内存泄漏?
- 使用Memory Profiler观察内存走势
- 在怀疑有内存泄漏的场景进行堆转储
- 分析堆转储文件,查找GC Root
- 使用LeakCanary等工具辅助检测
Q2: 为什么Handler容易造成内存泄漏?
- Handler内部类持有外部Activity的引用
- 消息队列中的Message持有Handler的引用
- 如果有延迟消息,会阻止Activity被回收
Q3: WeakReference的作用是什么?
- 弱引用不会阻止对象被垃圾回收
- 适合用于缓存场景
- 可以用来解决内存泄漏问题