引用计数算法(Reference Counting)
垃圾回收的困难不在于 实际回收垃圾的过程,而是在于在哪些地方找到垃圾。当一个对象不在被引用时候 则这个对象被认为是可以被回收的。
算法描述:
在每个对象中有个一个字段refCount 记录该对象被引用的次数,refCount是在java program 中不能被访问的,只是可以被jvm 修改或者更新。
例如:
Object p = new Integer (57);
当创建一个Integer 类的实例,只有一个变量p 指向这个对象,因为这个引用计数refCount=1
接着考虑下面的语句:
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去回收这个对象。
引用计数的开销在两个方面:
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.
C:Reference Counting 算法失效:
如图a所示循环的单链表,head 变量指向单链表的头,并且这个单链表的最后一个元素也指向单链表的头。 因为对于第一个元素的refCount=2,在链表中的其他元素的refCount=1
Figure: Why reference counting fails.
接下来,我们把head变量的值设置为null,head=null. 如图b所表示,链表的第一个元素的refCount减少了因为head变量不在指向它,但是它的refCount !=0,因为链表的最后一个元素指向链表的第一个元素。
现在我们遇到一个问题:在链表中的所有元素的refCount !=0,因而他们不会给gc.但是对于LinkedList 对象没有外部引用,LinkedList对象里的元素实际上是要被回收的。
总的来说,引用计数算法在碰到循环引用时候将不会奏效。但是JAVA 对于循环结构的构建是不会预防的。因此,引用计数算法对于复杂对象来说本身不是一个适合的垃圾回收模式。但是对于那些不指向其他对象的简单对象,这个是一个非常有用技巧。
- 大小: 1.5 KB
- 大小: 2.3 KB
- 大小: 4.4 KB
- 大小: 3.3 KB
分享到:
相关推荐
1. **引用计数算法(Reference Counting Collector)**:这是一种最直观的回收策略,为每个对象维护一个引用计数器,每当有一个地方引用它时,计数器加一;当引用失效时,计数器减一。当计数器为零时,对象可被回收...
引用计数算法是通过跟踪记录每个对象被引用的次数来判断是否需要回收,但它不能处理循环引用的问题。标记-清除算法分为标记和清除两个阶段,先标记出所有存活对象,然后清除未被标记的对象。复制算法则是将内存分为...
- 引用计数(Reference Counting):简单易实现,但处理循环引用时会失败。 - 根集追踪(Mark-and-Sweep):从一组根对象出发,遍历所有可达对象,并标记为存活。之后清理未被标记的对象。分为标记和清除两个阶段...
在JVM中,垃圾收集器(Garbage Collector,简称GC)会追踪所有活跃对象(正在使用中的对象),并将剩余的对象视为垃圾(即不可达对象),通过一系列算法来决定何时、如何回收这些垃圾对象。 ### GC算法 GC算法包括...
与Java不同,Python采用的是引用计数(Reference Counting)机制配合循环垃圾检测器(Cyclic Garbage Collector)。引用计数机制通过记录对象引用的个数来确定对象是否可以被回收,当对象的引用数为0时,意味着没有...
- **Reference Counting(引用计数)**:通过记录对象被引用的次数来决定是否回收。 - **跟踪收集器**:通过跟踪对象之间的引用关系来识别垃圾。 - **串行收集器**:在单个线程中完成垃圾回收工作。 - **并行收集器**...
1. **引用计数法(Reference Counting)**:简单但不能处理循环引用。 2. **标记-清除(Mark-Sweep)**:标记所有活动对象,然后清除未标记对象,容易产生内存碎片。 3. **复制(Copying)**:将对象复制到另一块内存,...
- **Reference Counting(引用计数)**:简单直观,但在处理循环引用时存在问题。 - **Tracking Collector(跟踪收集器)**:基于可达性分析算法,有效处理循环引用。 ##### 3.3 JVM的垃圾收集策略 ###### 3.3.1 ...
1. **引用计数(Reference Counting)**:每个对象包含一个引用计数器,当对象被引用时,计数器加一;当引用被释放时,计数器减一。当计数器归零时,对象可被回收。但这种方法无法处理循环引用的问题。 2. **追踪标记...
- **引用计数 (Reference Counting)**:通过跟踪每个对象的引用数量来决定是否回收。 - **跟踪收集器 (Tracing Garbage Collectors)**:基于可达性分析来确定哪些对象不再被引用,从而进行回收。 ##### 3.3 JVM的...
- **Reference Counting (引用计数)**:通过跟踪对象的引用数量来确定是否可以回收。 - **Tracking Collector (跟踪收集器)**:基于可达性分析来判断对象是否可回收。 ##### 3.3 JVM 的垃圾收集策略 JVM 使用多种...
4. **垃圾回收算法**:除了基础的引用计数,Hoa\Memory可能实现了一套自定义的垃圾回收机制,以更有效地回收不再使用的内存。 5. **内存分析工具**:为了帮助开发者调试和优化内存使用,Hoa\Memory可能包含了内存...