JAVA内存泄漏

JAVA内存泄漏

1.介绍
Java的一个重要特性是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己释放内存,理论上Java中所有不会再被使用的对象所占用的内存都可以被GC回收,但是Java还是存在内存泄漏。

2.内存分配
在Java程序中,我们通常使用new为对象分配内存,这些内存空间都在堆(Heap)上。例如:

public class Demo1 {
    public static void main(String[] args) {
        Object object1 = new Object();
        Object object2 = new Object();
        object2=object1;
        //此时object2是可以被清理的
    }
}

内存的释放,也就是清理那些不可达的对象,是由GC决定和执行的,所以GC会监控每一个对象的状态,包含申请,引用,被引用和赋值等等。释放对象的根本原则就是对象不会再被使用:
1)给对象赋予了空值null,之后再没有调用过。
2)另一个是给对象赋予了新值,这样重新分配了内存空间。

通常来说会认为在堆上分配对象的代价比较大,但是GC却优化了这一操作:C++中,在堆上分配一块内存,会查找一块适用的内存加以分配,如果对象销毁,这块内存就可以重用;而在java中就像一条长带子,每分配一个新的对象,java的"堆指针"就会向后移动到尚未分配的区域,分配内存的效率可与c++媲美。

但是如果频繁的申请内存,资源将会耗尽,这时GC就介入了,他会回收空间,并使堆中的对象排列更紧凑,这样始终会有足够大的内存空间可以分配。

GC清理时的引用计数方式:当引用连接至新对象时,引用计数+1,;当某个引用离开作用域或被设置为null时,引用计数-1;GC发现这个计数为0时,就回收其占用的内存。这个开销会在引用程序的整个生命周期发生,并且不能处理循环引用的情况。

3.内存泄漏
java的内存泄漏:不再会被使用的对象的内存不能被回收。在c++中所有被分配了内存的对象,不再使用后,都必须程序员手动释放他们。所以每个类,都有一个析构函数,作用是完成清理工作。但是在java中,无用的对象由GC自动清理,但实际有时候一些不会再被使用的对象,在GC看来不能被释放,就会造成内存泄漏。

对象都是有生命周期的,有的长,有的短,如果长生命周期的对象持有短生命周期的引用,就很可能出现内存泄漏,例如:

public class Demo2 {

    Object o;

    public void method() {
    	//new Object() 是对象,而o是new Object()这个对象的引用相当于一个指针,也可以说是new Object()的地址。
    	//new Object()是长生命周期的对象,而o是短生命周期的引用
        o = new Object();
        //...其他代码
    }

}

这里的object实例,我们只希望他作用于method方法中,但是当method方法执行完成后,object对象所分配的内存不会马上被认为是可以被释放的对象,只有在Demo2类创建的对象被释放后才会被释放。对此我们可以有两种方法:

1)将object类作为method方法的局部变量。

public class Demo2 {

    Object o;

    public void method() {
        Object  o1 = new Object();
        //...其他代码
    }

}

2)在方法最后将object对象赋值为null。

public class Demo2 {

    Object o;

    public void method() {
        o = new Object();
        //...其他代码
        o = null;
    }

}

4.一些内存泄露的例子和解决方法

1)

public class Demo3 {
    public void method() {
        Vector<Object> vector = new Vector<>();
        for (int i = 0; i < 100; i++) {
            Object object = new Object();
            vector.add(object);
            object = null;
        }
        //...对vector的操作
        //...与vector无关的操作
    }
}

如果对vector操作完成之后,执行与vector无关的代码时,发生了GC操作,这一系列的object是无法回收的,不过此处的内存泄漏可能是短暂的,在整个method方法执行完成后,那些对象还是可以被回收的。

对此我们可以这样:

public class Demo3 {
    public void method() {
        Vector<Object> vector = new Vector<>();
        for (int i = 0; i < 100; i++) {
            Object object = new Object();
            vector.add(object);
            object = null;
        }
        //...对vector的操作
        vector = null;
        //...与vector无关的操作
    }
}

整理借鉴了很多大佬写的,在此无法一一说明,这只是个人用来查漏补缺的文章,如果对你有帮助我很高兴。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值