Android 常见内存泄漏

亦凉 2023-10-17 13:49 120阅读 0赞

内存泄漏(Menory Leak)

进程中某些对象已经没有使用价值,但是他们却还是直接或间接地被引用到GC Root导致无法回收。

内存溢出(OOM)

当内存泄漏过多时,再加上应用本身占有的内存,日积月累最终就会导致内存溢出。

专业说法: 当应用占用的heap资源超过了虚拟机分配的内存就会内存溢出,比如加载大图片。

内存泄漏的影响

  • 应用卡顿

    • 泄漏的内存影响GC的内存分配,过多的内存泄漏会影响应用的执行效率
  • 应用异常(OOM)

    • 过多的内存泄漏,最终导致虚拟机可分配的内存越来越少,更加容易出现OOM
1. 静态变量、单例引用Activity和View

一直持有着Activity、View的引用,导致Activity无法被释放。静态变量、单例的Context不要传入Activity。

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. SingleTon.getInstance(this); //错误
  7. SingleTon.getInstance(getApplication()()); //正确
  8. }
  9. }
2. 非静态内部类(包括匿名内部类)

在java中,非静态内部类会隐式持有外部类,如果内部类没有被释放,那么外部类也不会被释放。
所以内部类应该使用static,这样可以避免内部类隐式持有外部类。

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. }
  7. public void show(String message) {
  8. Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
  9. }
  10. static class Inner {
  11. private Reference<MainActivity> activityRef;
  12. public Inner(MainActivity activity) {
  13. this.activityRef = new WeakReference(activity);
  14. }
  15. public void method1() {
  16. MainActivity activity = this.activityRef.get();
  17. if (activity == null) {
  18. return; //activity为null说明activity已经被回收了
  19. }
  20. //调用activity
  21. activity.show("hello world!");
  22. }
  23. }
  24. }

比如Handler等,应使用静态内部类。

(2). 匿名内部类
匿名内部类对外部类都持有一个隐式引用。
比如AsyncTask和Thread,如果在Activity销毁前,任务还未完成,那么将导致Activity的内存资源无法回收,造成内存泄漏。

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. new Thread() {
  7. @Override
  8. public void run() {
  9. SystemClock.sleep(100 * 10);
  10. }
  11. }.start();
  12. }
  13. }

应该使用静态内部类来解决

3. 不需要的监听未移除

注册的监听需要在不使用的时候注销

(1).自己的监听

  1. public class ThirdActivity extends AppCompatActivity
  2. implements NotifyController.UpdateCallback {
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_third);
  7. NotifyController.registerCallback(this);
  8. }
  9. @Override
  10. protected void onDestroy() {
  11. super.onDestroy();
  12. //结束时应移除监听
  13. NotifyController.unregisterCallback(this);
  14. }
  15. }

(2).系统的监听-示例1

  1. SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  2. Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
  3. sensorManager.registerListener(this, SensorManager.SENSOR_DELAY_FASTEST);
  4. //不用的时候,需要取消监听
  5. sensorManager.unregisterListener(this);

(3).系统的监听-示例2

  1. getWindow().getDecorView().getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
  2. @Override
  3. public void onWindowFocusChanged(boolean b) {
  4. //监听VIew的加载,View加载出来的时候,计算他的宽高
  5. }
  6. });
  7. //不用的时候,需要取消监听
  8. getWindow().getDecorView().getViewTreeObserver().removeOnWindowFocusChangeListener(this);
4.资源未关闭

对于使用BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会回收,造成内存泄漏。

Bitmap的回收

5. 无限循环动画

如果动画时无限循环的,记得要在Activity结束时,将其停止。

其他

参考
Android性能优化-内存泄漏的8个Case
Android 内存泄漏分析
Android开发必备技能:关于你所不知道的内存管理
Android OOM案例分析

发表评论

表情:
评论列表 (有 0 条评论,120人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Android 常见内存泄漏

    内存泄漏(Menory Leak) 进程中某些对象已经没有使用价值,但是他们却还是直接或间接地被引用到GC Root导致无法回收。 内存溢出(OOM) 当内存泄漏

    相关 Android 内存泄漏

    内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃(OOM)等严重后果。

    相关 Android 内存泄漏

    我们在面试的时候面试官有可能会问到这样关于内存的问题,希望对大家有所帮助。   首先我们要来了解一下什么是内存泄漏?    Java内存泄漏指的是进程中某些对象(垃圾对象)

    相关 Android 内存泄漏总结

    Java中的内存泄漏 java内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收。在Java中,