与C++一样,Java程序中同样会发生内存泄露的问题,但是Java中引入了垃圾回收机制。这里所说的垃圾就是那些泄露的内存。
在Java语言中,没有引用句柄指向的类对象最容易成为垃圾。产生垃圾的情况有很多,主要有以下3种:
(1) 超出对象的引用句柄的作用域时,这个引用句柄引用的对象就变成垃圾。
例:
{
Person p1 = new Person();
……
}
引用句柄p1的作用域是从定义到“}”处,执行完这对大括号中的所有代码后,产生的Person对象就会变成垃圾,因为引用这个对象的句柄p1已超过其作用域,p1已经无效,Person对象不再被任何句柄引用了。
(2) 没有超出对象的引用句柄的作用域时,给这个引用句柄赋值为空时,这个引用句柄引用的对象就变成垃圾。
例:
{
Person p1 = new Person();
…..
p1 = null;
….
}
在执行完“p1=null;”后,即使句柄p1还没有超出其作用域,仍然有效,但它已被赋值为空,不再指向任何对象,则这个Person对象不再被任何句柄引用,变成了垃圾。此后p1还可以指向其它Person对象,因为还没有超出它的作用域。
(3) 创建匿名对象时,匿名对象用完以后即成垃圾。
例:
{
new Person(); //因为是匿名对象,没有引用句柄指向它,即为垃圾
new Person().print();
//当运行完匿名对象的print()方法,这个对象也变成了垃圾
……
}
因此,在程序中应尽量少用匿名对象。
Java中的对象销毁:
Java语言没有提供析构函数,要解决内存泄露的问题,要销毁不再被引用的对象,就要借助其它方法,因此Java提供了一种非常好的机制:垃圾回收机制,即Garbage Collector,简称GC。
在Java中,不再被引用的对象所占据的内存由一个低优先级的垃圾回收线程自动回收。这个线程是在我们程序的执行过程中在后台持续运行的。在Java程序运行过程中,一个垃圾回收器会不定时地被唤起检查是否有不再被使用的对象,并释放它们占用的内存空间。垃圾回收器的回收无规律可循,可能在程序的运行的过程中,一次也没有启动,也可能启动很多次。因此,并不会因为程序代码一产生垃圾,垃圾回收器就马上被唤起而自动回收垃圾,很可能到程序结束时垃圾回收器都没有启动。所以垃圾回收器并不能完全避免内存泄漏的问题。
正因为垃圾回收器启动的无规律性,Java又提供了一种强制启动垃圾回收器的方法:System.gc()方法。在程序中显式地加入这个语句,就会强制启动垃圾回收器。垃圾回收器启动后,就会等待时机释放不再被引用的对象所占据的内存空间。但并不是一启动垃圾回收器,它就马上回收垃圾,如果这时有高优先级的线程仍在运行,回收垃圾的线程需要等待这个高优先级的线程执行完毕以后才可执行。
另一方面,垃圾回收会给系统资源带来额外的负担和时空开销。它被启动的几率越小,带来的负担的几率就越小。因此,不提倡在程序代码中加入大量的System.gc()语句。
正因为垃圾回收器的自动回收功能,保证了Java开发的程序在长期运行期间产生比较少的内存泄露,提高了系统的性能,方便了用户的使用。