内存泄漏的学习

内存泄漏介绍

内存泄漏是针对与堆内存而言的。

Java的内存管理就是对象的分配和释放。内存分配是由程序进行的,内存的释放是由GC完成。GC只能回收那些无用,且不被其他对象引用的对象们占用的空间。
从Main方法开始延伸,所有可以到达的对象都是有效对象,组成对象集合,这些不能被回收。其他的孤立对象则是GC回收的目标。

    {
        Object o = new Object();
    }

局部变量的生命周期是在大括号结束。这时候,栈内的o被销毁,则 new Object() 这个对象不在被引用,成为孤立对象,会被GC回收。
所以,内存泄漏的根本原因是:堆内存中的长生命周期的对象持有短生命周期对象的强/软引用,尽管短生命周期对象已经不再需要,但因为长生命周期对象持有对他的引用而导致他不能被回收。

常见的内存泄漏

  • 集合

    集合如果只有添加方法,没有删除方法,内存会被大量占用。如果集合是全局的,会造成内存只增不减。
    
  • 单例

    单例对象在被初始化后会在JVM整个生命周期中存在,如果单例持有了外部对象,会造成外部对象不能被回收,致使内存泄漏。

public class Test{
    private static Test test;
    private Context context;

    private Test(Context context){
        this.context = context;
    }

    public static Test getInstance(Context context){
        if(test == null){
            test = new Test(context);
        }

        return test;
    }
}

如果传入的context是一个activity,会使activity一直存在于内存中,不能被释放。

  • Android中的各种组件

    BroadCastReceiver,ContentObserver,Cursor等,在Regist后,记得在结束时调用unRegister或close(),并且,不要将Activity作为成员变量使用,例如上面单例的使用。如果一定需要,则记得使用 WeakReference。

  • 非静态内部类

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

    class TestResource {
    //...
    }
}

外部类的静态成员mResource的生命周期是整个程序的运行时间,而内部类的对象默认持有对外部类对象的一个引用,所以会导致Activity无法得到释放。
可以将内部类定义为静态内部类,则可以将内部类和外部类的对象的关系切断,只与类有关。

  • 线程造成的内存泄漏

    因为线程的生命周期不可控,如果线程保存了对外部对象的引用,会造成外部对象的不可释放。

  • Handler造成的内存泄漏

    如果handler发送的message没有被处理,那么MessageQueue将一直保留对handler,message的引用,而且handler与Activity的生命周期并不一致,可能会导致activity不能顺利释放。

public class SampleActivity extends Activity {

private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mLeakyHandler.postDelayed(new Runnable() {
      @Override
      public void run() { /* ... */ }
    }, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
    }
}

以上代码,发送了延时的消息,这消息并未被处理时,该页面退出会导致该页面无法被回收。

注意事项

  • 对activity的引用要考虑activity的生命周期,不过不能控制在其生命周期内,可以考虑用getApplicationContext(),避免activity长时间被占用。
  • 尽量不要在静态内部类使用非静态的成员变量,必须要用,也要在适当的时候将其置为空;也可以在静态内部类中使用弱引用来引用外部成员变量。
  • Handler持有的引用对象最好为弱引用,资源释放的时候可以清空handler中的消息。
  • 线程处理耗时操作,在页面返回时即使取消。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值