算法原理
引用记数法在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活的对象,哪些是已经死亡的对象,只有被标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间。
比如说,当我们编写以下代码时
String p = new String("abc")
abc这个字符串对象的引用计数值为1.
而当我们去除abc字符串对象的引用时,则abc字符串对象的引用计数减1
p = null
由此可见,当对象的引用计数为0时,垃圾回收就发生了。
引用计数算法很简单,它实际上是通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用,则它的引用计数加一,
如果删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。
严重问题
引用记数法有一个严重的问题,即无法处理循环引用的情况。一个简单的循环引用问题的描述如下:有对象A和对象B,对象A中含有对象B的引用,对象B中含有
对象A的引用。此时,对象A和对象B的引用计数器都不为0,但是在系统中却不存在任何第3个对象引用了A或B。也就是说,A和B是应该被回收的垃圾对象,但是由于
垃圾对象之间相互引用,从而使垃圾回收器无法识别,引起内存泄漏。
将最后一个元素的next属性指向第一个元素,即引用第一个元素,从而构成循环引用。这个时候如果将列表的头head赋值为null,此时列表的各个元素的计数器都不为0,同时也失去了对列表的引用
控制,从而导致列表元素不能被回收。
引用计数器拥有一些特性,首先它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。其次,每次赋值都需要更新计数器,这增加了时间开销。再者,垃圾对象便于辨识,只要计数器为0,就可作为垃圾回收
,接下来它能方便及时的回收垃圾,没有延迟性最后不能解决循环引用的问题,正是由于最后一条知名缺陷,导致在java的垃圾回收器中没有使用这类算法。