由于Java对象主要存放在Java堆里,因此垃圾收集器(Garbage Collection)在对Java堆进行回收前,第一件事情就是要肯定这些对象之中哪些还“存活”着,哪些已经“死去”(不被引用了)。java
引用计数算法,很容易理解,在对象中添加一个引用计数器,每有一个地方引用它时,计数器值就加一;当引用失效是,计数器值就减一;任什么时候刻计数器为零的对象就是不能够能再被使用的对象。
引用计数算法的原理简单,断定效率也很高。市面上也确实有一些技术使用的此类算法来断定对象是否存活,像ActionScript 3 的FlashPlayer、Python语言等。可是在主流的Java虚拟机里面都没有选用引用计算法来管理内存,主要是使用此算法时,必需要配合大量的额外处理才能保证正确的工做,例如要解决对象之间的相互循环引用的问题。算法
public class OneTest { public Object oneTest = null; private static final int _1MB = 1024 * 1024; private byte[] bigSize = new byte[256 * _1MB]; /** * 这个成员属性的惟一意义就是占点内存,以便能在GC日志中看清楚是否有回收过。 */ @Test public void testGC(){ OneTest test1 = new OneTest(); OneTest test2 = new OneTest(); test1.oneTest = test2; test2.oneTest = test1; test1 = null; test2 = null; // 假设在这行发生GC,test1和test2是否能被回收? System.gc(); } }
分析代码,test1和test2对象都被设置成了null,在后面发生GC的时候,若是按照引用计数算法,这两个对象虽然都被设置成了null,可是test1引用了test2,test2又引用了test1,因此这两个对象的引用计数值都不为0,因此都不会被回收,可是真正的实际运行结果是,这两个对象都被回收了,这也说明HotSpot虚拟机并非用引用计数法来进行的内存管理。缓存
当前主流的商用程序语言(Java、C#等),都是经过可达性分析(Reachability Analysis)算法来判断对象是否存活的。这个算法的基本思路就是经过一一系列称为“GC Roots” 的根对象做为起始节点集,从这些节点开始根据引用关系向下搜索,搜索走过的的路径称为“引用链”(Reference Chain),若是某个对象到GC Roots 间没有任何引用链相连,或者从GC Roots 到这个对象不可达时,则证实此对象是不可能再被使用的。
以下图,object十、object十一、object12这三个对象,虽然互相有关联,可是它们到GC Roots是不可达的,所以它们会被断定为可回收的对象。
在Java程序中,固定可做为GC Roots 的对象包括如下几种:线程
不管是经过引用计数算法判断对象的引用数量,仍是经过可达性分析算法判断对象是否引用链可达,判断对象是否存活都和“引用”离不开关系。在JDK1.2以前,Java里对引用的概念是:若是reference类型的数据中存储的数值表明的是另一块儿内存的地址,就称该reference数据是表明某块内存、某个对象的引用。
在JDK1.2版以后,Java对引用的概念进行了扩充,将引用分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。设计
Object obj = new Object()
这种引用关系。不管在任何状况下,只要强引用关系还存在,垃圾收集器就不会回收掉被引用的对象。日志
即便在可达性分析算法中,判断为不可达的对象,也不是“非死不可”的,要真正宣告一个对象死亡,至少要经历两次标记过程:code
须要注意的是:任何一个对象的finalize()方法都只会被系统自动调用一次,若是对象面临第二次回收,它的finalize()方法不会被再次执行。
还有一点就是Java官方已经明确声明不推荐手动调用finalize()方法了,由于它的运行代价高昂,不肯定性大,没法保证各个对象的调用顺序,而且finanlize()能作的全部工做,使用try-finally或其余方式均可以作的更好、更及时。对象
方法区垃圾收集的“性价比”一般比较低,而且方法区回收也有过于苛刻的断定条件。
方法区的垃圾收集主要回收两部份内容:废弃的常量和再也不使用的类型,回收废弃常量时,若是当前系统没有一个常量的值是当前常量值,且虚拟机中也没有其余地方引用这个常量。若是这个时候发生垃圾回收,常量就会被系统清理出常量池。
断定一个类型是否属于“再也不使用的类”的条件就比较苛刻了,要同时知足以下三个条件:blog
同时知足了上述的三个条件后,也只是被容许进行回收了,关因而否要对类型进行回收还要对虚拟机进行一系列的参数设置,这里就不赘述了,感兴趣的能够本身去查询。队列