java 垃圾回收机制-垃圾区分与标记
java的垃圾回收机制
垃圾收集GC是垃圾回收机制的核心,也是java语言的核心之一,在java中,程序员不需要过多地关心内存的动态分配关系和内存回收处理的问题,jvm(java虚拟机)会自动处理这些事情。
什么情况下的对象算是垃圾?
对于java对象来说,如果这个对象没有被其它的对象所引用,那么jvm就会判断这个对象为无用对象,也就是所谓的垃圾。在适当的时间jvm会自动销毁它占用的内存。
如何将这些垃圾区分出来并且标记呢?
java中标记垃圾的算法主要有两种,引用计数法和可达性分析算法。
引用计数法
引用计算法其实就像给对象装上了一个计数器,每当这个对象被引用,它的计数器就会加1,当引用失效以后,它的计数器就会减1。如果一个对象的计数器为0,那么就会判定是不再使用的对象,可以当做垃圾来收集。
优点:执行的效率高,对程序执行的影响较小
缺点:无法处理循环引用的情况,会导致内存泄露
循环调用的例子,
public class TestObject {
public TestObject obj;
}
public class ReferenceProblem {
public static void main(String[] args) {
TestObject object1 = new TestObject();
TestObject object2 = new TestObject();
object1.obj = object2;
object2.obj = object1;
}
}
因为object1和object2互相引用,所以不会被判定为垃圾对象,但是很明显这两个对象没有任何意义。这种情况就被称为循环引用,会造成内存泄露。
可达性分析算法
可达性算法是通过一系列称为“GC Roots”的对象作为起点,从这些起点开始向下搜索,节点所走过的路径称为引用链,如果一个对象到“GC Roots”没有引用链的话,就会被当做是不可用的对象,而被归类为垃圾对象。
哪些对象可以作为GCRoot?
1.虚拟机栈中的引用对象
2.方法区中的常量引用对象
3.方法区中的类静态属性引用对象
4.本地方法栈中的引用对象
5.活跃线程中的引用对象
蓝色的对象因为和GC Roots有引用链相连,所以是可用对象,白色对象与GC Roots没有引用链相连最后会被判定为无用对象。
在可达分析性算法中不可到达的对象,相当于处于“缓行时期”,它们并不会马上被处理掉,要真正宣告一个对象死亡,至少要经过两次的标记过程。在可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选条件是此对象是否有必要执行finalize方法。如果对象没有覆盖过finalize方法,或者该方法已经被虚拟机调用过,虚拟机将这两种情况视为没有必要执行。被判定为需要执行的对象将会被放在一个队列中(放置在F-Queue的队列中)进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被回收。