当前位置:   article > 正文

Android内存泄漏如何避免_在 android 中如何避免内存泄漏

在 android 中如何避免内存泄漏

1. 内存泄漏

是指程序中动态分配的堆内存由于某种原因没有及时回收,造成系统内存的浪费,导致程序运行变慢甚至是崩溃的结果。

根本原因:
一个生命周期较长的对象,强引用持有了一个生命周期较短的对象,导致短生命周期的对象在应该被销毁的时候没有被销毁。

2. 具体场景和避免办法

2.1 单例模式

项目中经常会用到一堆的工具类,有些工具类基本上就是全局单例的模式,而且它们在使用的时候又会经常的需要用到Context这个上下文变量,当传入这个变量的时候,这些工具类就会持有对应Activity的强引用了。

public class SingleInstance {
    //像这样的单例工具类,调用的时候都是直接使用instance变量
    //要更新的时候就会调用newInstance
    private static SingleInstance instance;
    private Context mContext;

    private SingleInstance(Context context){
        mContext = context;
    }

    private static SingleInstance getInstance(Context context){
        if (instance == null)
            return new SingleInstance(context);
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
public class MainActivity extends AppCompatActivity {

    private static MainActivity instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance = this;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这种情况下Activity退出后,由于这些单例还持有Activity的强引用,所以导致分配给Activity的堆内存就没法回收,这就造成了内存泄漏。

避免办法:

  1. 一些生命周期比较短的对象,不要作为成员变量传入,也不要被任何长期对象持有。
  2. 用弱引用代替强引用,这样不会阻拦GC回收对象。
public class SingleInstance {
    //像这样的单例工具类,调用的时候都是直接使用instance变量
    //要更新的时候就会调用newInstance
    private static SingleInstance instance;
    private Context mContext;

    private SingleInstance(){}

	private fun(Context context) {
		//  处理逻辑
	}

    private static SingleInstance getInstance(){
        if (instance == null)
            return new SingleInstance();
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
```java
public class MainActivity extends AppCompatActivity {

    private static WeakReference<MainActivity> instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance = new WeakReference<>(this);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.2 非静态内部类

在Java中,非静态内部类会隐形持有外部类的引用,而且是强引用。

2.2.1 内部类/匿名内部类

有时候经常会需要临时new一个Thread出来工作的情况,这种时候这个临时工线程就会拥有Activity的引用了,这种情况下如果Activity退出销毁后,也不会回收内存,这就又造成内存泄漏了。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //假装在做耗时的工作
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2.2.2 Handler

还有Handler的内部类使用,我们经常也是这么用的,这个就更夸张了,Android Studio就直接报警告提醒你会内存泄漏了。
Handler的生存周期并不会因为你是写在Activity里面就和Activity一样,所以会造成内存泄漏。
在这里插入图片描述

2.2.3 AsyncTask

这个也是会不经意间就直接写成Activity内部类的类型,也会持有Activity的强引用。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		new MyasyncTask().execute();
	}

    static class MyAscnyTask extends AsyncTask<Void, Void, Void>{
        @Override
        protected Void doInBackground(Void... params) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

避免办法:

  1. 还是和之前一样,改用弱引用来代替强引用。
  2. 使用静态变量,这样就无法持有外部类的引用了。

2.3 集合/静态集合

在开发过程中经常会有用到集合的时候,集合内的元素会随着添加而越来越多,如果是静态集合那么生命周期会和应用程序一样长,这样就非常占内存。

 static List<Object> objectList = new ArrayList<>();
 for (int i = 0; i < 10; i++) {
     Object obj = new Object();
     objectList.add(obj);
     obj = null;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

避免办法:用不到的集合元素要及时的清理。

2.4 静态变量

静态变量本身的生命周期就和应用程序一样长,不当的使用自然会造成内存泄漏。
避免办法:正确的使用静态变量…之前说的集合那些就避免用静态变量就行了,不得不用的时候就记得清理。

2.5 资源未释放

在开发过程中,经常会有应该及时关闭/释放的对象却没有记得这么做,这里就列举一下有哪些

  • Service:bindService()忘记unbindService()。
  • BroadcastReceiver:registerReceiver()后忘记unregisterReceiver()。
  • 文件流,SQLite等需要关闭的对象:open()之后忘记close()。
  • 加载的图片资源Bitmap:这个是图片,占内存比较多,不用的时候一定要记得关闭,调用recycle()方法。

参考材料

Android 关于内存泄露,你必须了解的东西 - 简书
https://www.jianshu.com/p/65f914e6a2f8
一篇技术好文之Android性能优化内存泄漏无处可藏(图文) - 简书
https://www.jianshu.com/p/86a6d5cd3b05

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/240325
推荐阅读
相关标签
  

闽ICP备14008679号