以下有三个问题:
1、那些内存需要回收?
java堆中创建的对象需要回收,以及方法区中的类需要卸载以及常量池需要回收。
2、什么时候回收?
JVM通过可达性算法分析,如果一个对象到GC roots对象之间没有链,则该对象就会被GC回收。如果判断一个对象可以被回收,就将该对象放入到F_Queue队列中,JVM会启动一个低优先级的Finalizer线程,去触发对象中的对象执行finalize()方法,如果该方法执行完毕,则该对象就被回收了。
3、如何回收?
根据不同的垃圾收集算法进行不同的回收。后面的文章会介绍。
4、如何判断一个对象是否“死了”(即不在被引用)?
(1)引用计数法,即一个给对对象添加一个计数值,被引用一次加1,引用失效时,减1。若引用计数值为0.则该对象“死了”。该方法有缺点,如果二个对象互相引用,则二个对象不会被GC回收。例如:
/**
* testGC()方法执行后,objA和objB会不会被GC呢?
*/
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
/**
* 这个成员属性的唯一意义就是占点内存,以便在能在GC日志中看清楚是否有回收过
*/
private byte[] bigSize = new byte[2 * _1MB];
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 假设在这行发生GC,objA和objB是否能被回收?
System.gc();
}
}
该对象被JVM的GC回收了,说明JVM不是使用引用计数法进行对象回收的。使用的是可达性分析。
(2)可达性分析法:算法 的基本思想就是从“GC roots”对象作为起点,从这些节点开始向下搜索,搜索所走的路径成为引用链,当一个对象到GCroots没有任何引用链相连时,该对象可以被回收了。
GC roots对象包括哪些?
(1)JVM栈中的本地变量表中的对象引用
(2)方法区中类静态属性引用对象
(3)方法区中的常量引用对象
(4)本地方法栈中得JNI引用对象
5、java中引用的类型?
什么叫引用呢?即在方法区中的本地变量表中的变量存储的值是java堆的地址,则该变量就叫做引用。
引用分为几种类型?
强引用:Object obj=new Object(),如果请引用一直存在的话,GC是不会回收当前的对象的。
软引用:使用SoftReference类来实现,当系统就要发生内存溢出异常之前,会对软引用对象进行回收,如果回收之后内存还不够,则会抛出内存异常。软引用对象,在响应内存需要时,由垃圾回收器决定是否清除此对象。软引用对象最常用于实现内存敏感的缓存。软可到达对象的所有软引用都要保证在虚拟机抛出OutOfMemoryError
之前已经被清除。否则,清除软引用的时间或者清除不同对象的一组此类引用的顺序将不受任何约束。然而,虚拟机实现不鼓励清除最近访问或使用过的软引用。
此类的直接实例可用于实现简单缓存;该类或其派生的子类还可用于更大型的数据结构,以实现更复杂的缓存。只要软引用的指示对象是强可到达对象,即正在实际使用的对象,就不会清除软引用。例如,通过保持最近使用的项的强指示对象,并由垃圾回收器决定是否放弃剩余的项,复杂的缓存可以防止放弃最近使用的项。
弱引用:使用WeekReference类来实现,当系统进行垃圾收集时,被弱引用实现的对象都会被回收。
弱引用对象,它们并不禁止其指示对象变得可终结,并被终结,然后被回收。弱引用最常用于实现规范化的映射。
假定垃圾回收器确定在某一时间点上某个对象是弱可到达对象。这时,它将自动清除针对此对象的所有弱引用,以及通过强引用链和软引用,可以从其到达该对象的针对任何其他弱可到达对象的所有弱引用。同时它将声明所有以前的弱可到达对象为可终结的。在同一时间或晚些时候,它将那些已经向引用队列注册的新清除的弱引用加入队列。
虚引用: 使用PhantomReference类来实现,该类不会影响该对象本身的生命周期,它唯一的作用就是当对象被GC回收时,会收到系统的通知。