Android内存泄漏


直入正题,首先说说什么是内存泄漏

一、什么是内存泄漏

内存泄漏是当程序向系统申请内存空间后,在使用完毕后未释放内存或释放内存失败,从而产生了无用的内存消耗。各位看官也可以顺道去了解一下垃圾回收机制(gc)。这里还是简单讲一下,当一个不可到达的对象时,在执行gc操作时会被回收,而当一个我们不再使用的数据依然是可到达的状态的时候,这就是发生了内存泄漏。

二、内存泄漏的影响

在说内存泄漏的影响之前大家需要先了解一下内存溢出,简单来说,内存溢出就是所需要的内存超出了系统为之分配的内存。
而过多的内存泄漏将会导致内存溢出,这将会导致应用出现Crash,这对用户来说将会是很不好的体验,所以在开发过程中我们应该尽量避免内存泄漏的发生。

三、常见的内存泄漏情形

在开发过程中发生内存泄漏的情况很多,下面我将对比较常见的内存泄漏情况进行简单说明

1.单例模式引发的内存泄漏

Android的单例模式非常受开发者的喜爱,不过使用的不恰当的话也会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。
下面给个单例发生内存泄漏的例子:

public class AppManager {private static AppManager instance;private Context context;private AppManager(Context context) {    this.context = context;}public static AppManager getInstance(Context context) {    if (instance != null) {        instance = new AppManager(context);    }    return instance;}}

当我们在初始化getInstance的时候传入的context为Activity的context的时候将会发生内存泄漏,因为在Activity退出时,activity本该被回收,但是由于单例模式持有了Activity的引用,而单例模式的生命周期和应用一样长,所以会导致Activity不能被回收,这也就导致了内存泄漏的发生。
避免方法:用Application的Context代替Activity的Context,因为Application的生命周期和单例是相同的,所以将不会有内存泄漏问题。

2.非静态内部类引发的内存泄漏

非静态内部内部类会默认持有外部类的引用,这在内部类与外部类的生命周期不相同的时候将会发生内存泄漏。
例:

public class MainActivity extends AppCompatActivity {private static DemoResource mResource = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    if(mManager == null){        mManager = new DemoResource();    }    //...}class DemoResource {    //...}}

由于DemoResource是非静态内部类,持有外部类的引用,而mResource 的生命周期和应用的相同,所以当activity结束时会发生内存泄漏。
避免方法:避免使用非静态内部类,尽量使用静态内部类。

3.Handler造成的内存泄漏

在开发过程中需要访问网络或一些耗时的操作时经常会使用Handler进行处理,这时候不加留意便会发生内存泄漏。(我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用)
下面举一个Handler内存泄漏的例子:

public class MainActivity extends AppCompatActivity {private Handler mHandler = new Handler() {    @Override    public void handleMessage(Message msg) {        //...    }};@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    loadData();}private void loadData(){    //...request//发送消息    Message message = Message.obtain();    mHandler.sendMessage(message);}}

这种写法相信很多同学都有过,然而这样将会造成内存泄漏,因为mHandler持有Activity的引用。在上面括号中的情况发生时会发生内存泄漏。
解决办法:
继承Handler写一个静态内部类,然后对Handler的持有对象使用弱引用,这样再回收是也可以回收handler持有的对象。并在Activity的Destroy时或者Stop时应该移除消息队列中的消息。
具体的示例如下:

public class MainActivity extends AppCompatActivity {private MyHandler mHandler = new MyHandler(this);private TextView mTextView ;private static class MyHandler extends Handler {    private WeakReference reference;    public MyHandler(Context context) {        reference = new WeakReference<>(context);    }    @Override    public void handleMessage(Message msg) {        MainActivity activity = (MainActivity) reference.get();        if(activity != null){            activity.mTextView.setText("");        }    }}@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mTextView = (TextView)findViewById(R.id.textview);    loadData();}private void loadData() {    //...request    Message message = Message.obtain();    mHandler.sendMessage(message);}@Overrideprotected void onDestroy() {    super.onDestroy();    mHandler.removeCallbacksAndMessages(null);}}

注意,因为使用的是弱引用持有数据,所以在使用时一定要先进行判Null,否则可能会造成空指针异常

4.线程造成的内存泄漏

对于线程造成的内存泄漏,也是平时比较常见的,废话不说,直接上示例:

new Thread(new Runnable() {        @Override        public void run() {            SystemClock.sleep(10000);            //延时操作        }    }).start();

上面的Runnable是一个匿名内部类,所以ta对activity有一个隐式的引用, 很明显ta进行了一个延时操作,当我们在现在还没有执行完之前关闭了这个activity,也就发生了内存泄漏。
解决办法:你都能猜到的方法,依然还是使用静态内部类。示例代码就不上了

5.资源未关闭造成的内存泄漏

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

总结

以上是在android开发中常见的内存泄漏情形,对于生命周期不一致的问题(其实前四种都可以看作这种情况),主要是采用静态内部类,还有就是合理使用弱引用(ps:大家也可以去看看弱引用、软引用、强引用等的区别),其他具体开发中的问题还需具体分析。对于资源,一定要及时关闭

更多相关文章

  1. Android内存机制分析——堆和栈
  2. 彻底解决Android 拍照 内存溢出 Out of Memory的问题
  3. Android内存泄漏的轻松解决方法
  4. 安卓Android的内存管理原理解析
  5. [置顶] Android 之 内存管理

随机推荐

  1. Android(安卓)开发规范
  2. Android:Activity生命周期
  3. Android环境配置(Eclipse全开发环境下载)
  4. Android(安卓)开发之环境的搭建
  5. Android使用SharedPreferences存储数据的
  6. Android开发指南(41) —— Searchable Co
  7. Android[中级教程]第四章 单元测试Androi
  8. [Android(安卓)Pro] Android开发实践:自定
  9. 杂谈-Android源码(AMS、PMS、WMS)及部分原
  10. android TDD平台插入双卡时,查看允许返回