创建对象会占据内存,如果程序执行流程中已无法再使用某个对象,该对象就只是徒耗内存的垃圾
对于不再有用的对象,JVM有垃圾收集机制(GC),收集到的垃圾对象所占据的内存空间,会被垃圾收集器释放。那么,哪些会被JVM认定为垃圾对象?简单地说,无法通过变量参考的对象,就是GC认定的垃圾对象。
在学习GC之前,你首先应该记住一个单词:“stop-the-world”。Stop-the-world会在任何一种GC算法中发生。Stop-the-world意味着 JVM 因为要执行GC而停止了应用程序的执行。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成。GC优化很多时候就是指减少Stop-the-world发生的时间。
Java的GC机制是自动进行的,和c语言有些区别需要程序员自己保证内存的使用和回收。
Java的内存分配和回收也主要在Java的堆上进行的,Java的堆中存储了大量的对象实例,所以Java的堆也叫GC堆。
Java在垃圾收集的过程中,主要用到了分代收集算法。
1、 假设有一个类:
public class Some{
Some next;
}
若是从程序进入点开始,有段代码如下:
Some some1 = new Some();
Some some2 = new Some();
Some some1 = some2 ;
执行到第二行是,主线程可以通过参考名称所参考到的对象,如图6.20所示。
执行到第三行时,是将some2参考的对象给some1参考,如图6.21所示。
原先some1参考的对象不再被任何名称参考,通过主线程也不再能参考到该对象,这个对象就是内存中的垃圾,GC会自动找出这些垃圾并给予回收。
GC的基本概念就是这样,但可以加以变化。如果有段程序是这样:
Some some = new Some();
some.next = new Some();
some = null;
在执行到第二行是,情况如图6.22所示,此时还没有对象是垃圾。
由于从主流程开始,可以通过some参考至中间的对象,而some.next可以参考至右边的对象,目前没有必要回收任何对象。执行完成第三行后,情况编程如图6.23所示。
由于从主流程开始,无法通过some参考至中间对象,也就无法再通过中间对象的next参考至右边对象,所以两个对象都是垃圾。同样的道理,下面程序代码中,数组参考到的对象全部都会被回收,如图6.24所示。
Some[] somes = {new Some(),new Some(),new Some};
somes = null;
被回收的对象包括了数组对象本身,以及三个索引所参考的三个对象。如果是形同孤岛的对象,例如
Some some = new Some();
some.next = new Some();
some.next.next = new Some();
some.next.next.next = some;
some = null;
执行到第四行时,情况如图6.25所示。
执行完第五行后,情况变为如图6.26所示。
提示:GC在进行回收对象前,会调用对象的finalize()方法,这是Object上定义的方法。如果在对象被回收前,有些事情想做,可以重新定义finalize()方法,不过要注意的是,何时启动GC,要视所采用的GC算法而定,也就是finalize()被调用的时机是无法确定的。在Effective Java 书中也建议,避免使用finalize()。如果对finalize()方法有兴趣,可以参考:
http://caterpillar.onlyfun.net/Gossip/JavaEssence/Finalize.html