用如下这段代码,可以说明
/** * 运行这段程序,需要在运行设置的VM Arguments中写入如下语句 * -verbose:gc * 它的作用是在控制台输出GC的详细信息。 * @author qianl * */ public class Test { public Object instance = null; private static final int _1M = 1024 * 1024; private byte[] size = new byte[2 * _1M]; //占用一点内存,以便在GC日志中观察是否被回收过 public static void main(String[] args) { // TODO Auto-generated method stub Test t1 = new Test(); Test t2 = new Test(); t1.instance = t2; //t2对象被引用,如果Java使用引用计数算法,那么其值+1 t2.instance = t1; //t1对象被引用,如果Java使用引用计数算法,那么其值+1 t1 = null; //t1为null,它的成员变量instance所引用的对象将不会被用到。 t2 = null; //t2为null,它的成员变量instance所引用的对象将不会被用到。 /** * 在此使用Java的垃圾回收,由上面代码可知,t1和t2两个对象将不可能被用到,但是他们的引用计数的值 * 却不为0,它们会被回收吗? */ System.gc(); } }
上面的内容,都涉及到一个名词:引用。那什么是引用?
通俗的解释为:一个reference类型的数据中存储的数值代表另外一块内存的起始地址,这块内存代表的就是一个引用。
其实,Java1.2以后,引用不止这么简单,有四种引用,分别为:强引用(如Object obj = new Object()),软引用、弱引用、虚引用。这里,我就抛砖引玉一下,大家想了解的可以Google或者度娘一下。(PS:因为我本人也不是很了解,呵呵)。
GC对方法区的回收是怎样判断的呢?
GC对于堆的回收,效率是比较高的,一次回收,基本上都可以回收百分之七八十的空间。而方法区,效率要低得多。
对于此部分,GC主要回收两部分:废弃常量和无用类。
废弃常量:如一个字符串“ABC”进入了常量池,但是系统中,没有一个String对象叫做“ABC”,即没有任何String对象引用它,那么,这个字符串就很可能被GC回收。常量池中的接口、方法、字段等都类似。
无用类:必须满足以下三个条件,才可能被GC回收
* 该类所有实例都已经被回收,即堆中不存在该类实例
* 加载该类的ClassLoader已经被回收
* 该类对应的java.lang.Class对象没有被任何地方引用,无法通过反射机制访问该类