内存泄漏(Memory Leak)是指程序在运行过程中,由于疏忽或错误未能释放不再使用的内存,导致这部分内存无法被回收,最终可能引发应用卡顿、崩溃或系统性能下降。
静态变量(如单例)持有 Activity 或 View 的引用,导致 Activity 销毁时无法被回收。
非静态内部类(如 Handler、Runnable)隐式持有外部类(如 Activity)的引用,若其生命周期长于外部类,会导致泄漏。
匿名内部类(如回调、监听器)隐式持有外部类的引用。
例如未在 onDestroy()
中移除 BroadcastReceiver
、LiveData
观察者等。
文件流、数据库游标(Cursor)等未及时关闭。
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}
WeakReference
持有 Activity 的引用: private static class MyHandler extends Handler {
private final WeakReference<Activity> activityRef;
MyHandler(Activity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
Activity activity = activityRef.get();
if (activity != null) {
// 更新 UI
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 移除 Handler 的消息
handler.removeCallbacksAndMessages(null);
// 注销广播接收器
unregisterReceiver(broadcastReceiver);
// 移除 LiveData 观察者
liveData.removeObserver(observer);
}
Application Context
代替 Activity Context
(例如单例模式中): public class MySingleton {
private static MySingleton instance;
private Context appContext;
private MySingleton(Context context) {
appContext = context.getApplicationContext();
}
public static MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
}
try {
InputStream is = new FileInputStream(...);
// 使用资源
} finally {
is.close(); // 确保资源被释放
}
内存泄漏的核心问题是长生命周期对象持有短生命周期对象的引用。通过合理使用弱引用、及时释放资源、借助工具分析,可以显著减少泄漏风险。在 Android 开发中,养成主动管理对象生命周期的习惯至关重要。
ANR 是 Android 系统中应用无响应的警告机制。当应用主线程(UI 线程)被长时间阻塞(如执行耗时操作),导致用户输入事件(点击、滑动等)或 BroadcastReceiver
无法在合理时间内处理,系统会弹出 ANR 弹窗,提示用户选择“等待”或“关闭应用”。
场景 | 超时阈值 | 原因 |
---|---|---|
输入事件(如点击、滑动)未响应 | 5 秒 | 主线程被耗时操作(如网络请求、复杂计算)阻塞。 |
| 前台 10 秒 / 后台 60 秒 | 在 |
| 前台 20 秒 |
|
BroadcastReceiver
或 ContentObserver
/data/anr/traces.txt
文件,记录主线程的堆栈信息:adb pull /data/anr/traces.txtThread.sleep()
、wait()
、锁竞争等)。 public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog() // 输出日志警告
.build());
}
}
viewModelScope.launch(Dispatchers.IO) {
// 执行网络请求或数据库操作
val result = api.fetchData()
withContext(Dispatchers.Main) {
updateUI(result) // 返回主线程更新 UI
}
}
Observable.fromCallable(() -> doBackgroundWork())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> updateUI(result));
onCreate()
、onResume()
中执行复杂逻辑。IdleHandler
处理低优先级任务: Looper.myQueue().addIdleHandler(() -> {
// 在主线程序列空闲时执行
return false; // true 表示保留 Handler,false 表示移除
});
BroadcastReceiver
onReceive()
中仅处理轻量级逻辑,如需耗时操作,启动 IntentService
或 WorkManager
: public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 启动 Service 处理耗时任务
Intent serviceIntent = new Intent(context, MyService.class);
context.startService(serviceIntent);
}
}
ListView
/RecyclerView
的过度绘制。ViewStub
延迟加载复杂视图。若线上发生 ANR,需快速定位问题:
traces.txt
或 Firebase 获取堆栈信息。 python systrace.py -t 10 sched gfx view wm am app
ANR 的核心矛盾是 主线程被阻塞导致用户交互无响应。通过以下原则可显著降低风险:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。