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 引用

使用 WeakReferenceApplication 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 内存泄漏的排查和修复技巧,提升应用的质量和性能。

相关推荐
雨白31 分钟前
重识 Java IO、NIO 与 OkIO
android·java
啦啦9117141 小时前
Niagara Launcher 全新Android桌面启动器!给手机换个门面!
android·智能手机
游戏开发爱好者81 小时前
iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
android·macos·ios·小程序·uni-app·iphone·webview
xrkhy1 小时前
canal1.1.8+mysql8.0+jdk17+redis的使用
android·redis·adb
00后程序员张2 小时前
混淆 iOS 类名与变量名的实战指南,多工具组合把混淆做成工程能力(混淆 iOS 类名变量名/IPA 成品混淆Ipa/Guard CLI 实操)
android·ios·小程序·https·uni-app·iphone·webview
介一安全3 小时前
【Frida Android】实战篇1:环境准备
android·网络安全·逆向·frida
许愿OvO4 小时前
MySQL触发器
android·mysql·adb
循环不息优化不止4 小时前
Jetpack Compose 从重组到副作用的全方位解析
android
2501_916007475 小时前
iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
android·macos·ios·小程序·uni-app·cocoa·iphone
Android疑难杂症6 小时前
鸿蒙Notification Kit通知服务开发快速指南
android·前端·harmonyos