天天看点

Reference Counting Garbage Collector 引用计数算法垃圾回收器

引用计数算法(Reference Counting)

垃圾回收的困难不在于 实际回收垃圾的过程,而是在于在哪些地方找到垃圾。当一个对象不在被引用时候 则这个对象被认为是可以被回收的。

算法描述:

在每个对象中有个一个字段refCount 记录该对象被引用的次数,refCount是在java program 中不能被访问的,只是可以被jvm 修改或者更新。

例如:

Object p = new Integer (57);

当创建一个Integer 类的实例,只有一个变量p 指向这个对象,因为这个引用计数refCount=1

Reference Counting Garbage Collector 引用计数算法垃圾回收器

接着考虑下面的语句:

Object p = new Integer (57);

Object q = p;

这个语句只是创建了一个integer 实例,p和q 都指向同一个对象,因为 这个实例的

refCount =2

总的来说,每次一个引用变量赋值给另外一个变量时候,总是有必要更新几个引用计数。假定p和q 都是引用变量,下面的赋值

p = q;

在jvm 中将会实现成如下伪代码:

if (p != q)

{

    if (p != null)

--p.refCount;

    p = q;

    if (p != null)

++p.refCount;

}

假如p,q初始化如下:

Object p = new Integer (57);

Object q = new Integer (99);

如图a所描述的,构造了2个integer 实例,每个实例的refCount=1/

接下来,我们把p=q。

如图b所描述的,在赋值之后,p和q都指向了同一个对象,这个对象的refCount=2,而对Integer(57)这个对象的引用已经变成了0,这只是gc去回收这个对象。

Reference Counting Garbage Collector 引用计数算法垃圾回收器

引用计数的开销在两个方面:

A:每个对象需要一个特殊的refCount 字段,在每个对象中 需要为这个字段分配额外的存储空间

B:每次一个引用被赋值给另外一个引用,这个refCount 就必须用上面的代码进行调整,这明显增加了赋值语句的执行时间。

引用的计数算法的优点:

垃圾回收器很容易定位出需要回收的对象,并且并不需要等到没有足够的空间才启动垃圾回收,当一个对象的refCount=0时,我们可以立即启动垃圾回收。

例如 p=q

if (p != q)

{

    if (p != null)

if (--p.refCount == 0)

    heap.release (p);

    p = q;

    if (p != null)

++p.refCount;

}

用上述方法,垃圾将会被增量回收。

B:指向复杂对象:

例如:

Object p = new Association (new Integer (57), new Integer (99));

图a描述了Object p = new Association (new Integer (57), new Integer (99));

这个语句执行完之后的内存内从。

Association  实例的引用数量refCount=1,因为之后一个变量p指向它。

相似的两个integer实例的refCount =1,因为之后一个Association 实例指向它们。

        图:当一个对象指向另一个对象的引用计数

Suppose we assign the value null to the variable p.

假定我们将p=null,如图b所描述,association实例的refCount=0,这个association实例就变得可以被回收了。

Association 这个实例会一直存在直到gc开始回收Association 。图d

描述了当Association 被gc时,,gc调整Association 实例引用的refCount 。经过调整之后 ,这两个Intege 对象的refCount=0也可以被gc.

Reference Counting Garbage Collector 引用计数算法垃圾回收器

C:Reference Counting 算法失效:

如图a所示循环的单链表,head 变量指向单链表的头,并且这个单链表的最后一个元素也指向单链表的头。 因为对于第一个元素的refCount=2,在链表中的其他元素的refCount=1

Reference Counting Garbage Collector 引用计数算法垃圾回收器

Figure: Why reference counting fails.

接下来,我们把head变量的值设置为null,head=null. 如图b所表示,链表的第一个元素的refCount减少了因为head变量不在指向它,但是它的refCount !=0,因为链表的最后一个元素指向链表的第一个元素。

  现在我们遇到一个问题:在链表中的所有元素的refCount !=0,因而他们不会给gc.但是对于LinkedList 对象没有外部引用,LinkedList对象里的元素实际上是要被回收的。

总的来说,引用计数算法在碰到循环引用时候将不会奏效。但是JAVA 对于循环结构的构建是不会预防的。因此,引用计数算法对于复杂对象来说本身不是一个适合的垃圾回收模式。但是对于那些不指向其他对象的简单对象,这个是一个非常有用技巧。