GC标记回收

来源:互联网 发布:免费路由软件 编辑:程序博客网 时间:2024/05/17 01:11

1.什么是GC

Garbage Collection简称为GC,是垃圾回收的意思、内存处理器是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃。Java语言提供的GC功能可以自动的检测对象是否超过作用域,从而达到自动回收内存的目的,java语言没有提供释放已分配内存的显示操作方法,资源回收工作全部交由GC来完成,程序员不能精确的控制垃圾回收的时机。

2.GC的标记

GC在java语言起到资源回收的作用,那么它是如何做到的呢?其实GC是通过一定的算法对需要回收的对象进行标记,符合条件的则进行资源回收。GC的标记方式主要有“引用计数”和“可达性分析”这两种。
(1)引用计数标记
引用计数标记实现起来比较简单,就是给对象添加一个引用计数器,每当有一个地方引用它时就加1,引用失效时就减1,当计数器为0的时候就标记为可回收。这种判断效率很高,但是很多主流的虚拟机并没有采用这种方法,因为其存在很大的局限性,因为它很难解决几个对象之间循环引用的问题,而往往在业务功能的实现需要多个对象的协同,像如下代码中的两个对象的相互引用会导致计数器不会变0即不会回收的情况

public class GCTest {    private Object o;    public void test(){        GCTest g1 = new GCTest();        GCTest g2 = new GCTest();        //相互引用        g1.o = g2;        g2.o = g1;    }}

(2)可达性分析标记
可达性分析标记的设计思路为:将一些可称为“GC Roots”的对象作为起始点,从这些节点开始搜索,搜索和该节点发生直接或者间接引用关系的对象,将这些对象以链的形式组合起来,形成一张“关系网”,又被称为引用链。最后垃圾收集器回收那些不在这张关系网上的对象。如下图:
这里写图片描述

连接GC Roots对象的object是确定还存活的对象,而下边的die Object虽然有引用关系,但是没有和GCROOTS有直接或间接的关系,所以会标记为可回收的对象。目前主流的商用虚拟机用的都是类似的方法,什么对象才能作为“GC Roots”呢?在java中,有四种对象可以作为“GC Roots”

1:栈帧中的引用对象。(栈中的)
2:静态属性引用的对象。(方法区中的)
3:常量引用的对象。(方法区中的)
4:本地方法栈中JNI引用的对象。(本地方法(Native)栈中的)

3.GC的二次标记

Object类有一个finalize()方法,所有类都继承了Object类,因此都会默认实现了这个方法。这个方法的用途是:在该对象被回收之前,该对象的finalize()方法会被调用。这里的回收之前指的就是被标记之后,但是会存在一种情况就是原本一个对象不在上面所讲的“关系网”(引用链)中,但是当开发者重写了finalize()后,并且将该对象重新加入到了“关系网”中,也就是说该对象在系统中还有用,不应该被回收,但是已经被标记了。针对这种情况,虚拟机的做法是进行两次标记,即第一次标记不在“关系网”中的对象。第二次的话就要先判断该对象有没有实现finalize()方法了,如果没有实现就直接判断该对象可回收;如果实现了就会先放在一个队列中,并由虚拟机建立的一个低优先级的线程去执行它,随后就会进行第二次的小规模标记,在这次被标记的对象就会真正的被回收了。

原创粉丝点击