需要通过引用计数处理的循环引用的真实示例

时间:2013-06-10 06:40:11

标签: garbage-collection

这可能是理论上的一点,我需要这个,因为我正在设计我自己的编程语言,作为一个爱好项目的乐趣。我认为记忆管理是“四代”。这是我自己的看法,与任何纸张或学校无关。

第一代是平坦的内存块,应用程序只管理它如何。

第二代是malloc / free style heap。系统将处理内存,但您处理对象。

第三代是引用计数分配/处置,它在“到位”或换句话说在调用new / delete期间发生。

第四代是你通常所说的垃圾收集器。在调用新/删除或其他过程期间,可能会发生在另一个线程中或有时像第三代一样的事情。

主要区别在于第4代GC有时会“走”或“扫描”堆对象,并检查其中一些是否“无根”,以便它可以删除tham。这是非常复杂的,有许多算法用于“扫描”。有时这些算法名称中有一个“颜色”字样。像“三色标记”或“三色计数异步并行”等。进行“堆扫描”的最明显原因是处理循环引用。因为没有(还有?)其他方式来处理它。

现在回答我的问题。

如果没有第4代GC,那么圆形参考的“真实生活”例子是什么?当然你可以输入两行代码,故意创建循环引用。但这不是我的问题。我想要一个“真实”的例子,我的意思是可以自然发生的事情,并且可以很容易理解。对于任何一个新的东西,你可以真正地展示出你需要用GC处理的循环引用。也许我也可以使用“实用”和“有用”的词语来描述这样的例子。

1 个答案:

答案 0 :(得分:2)

因为您要求使用LinkedList这是一个真实的示例,这是Java中的一个示例:

{
    List<String> list = new LinkedList<String>();
    list.add("hello");
    list.add("world");
}

为什么这里有一个循环?因为Java的LinkedList是一个双向链表,而the implementation of its add是:

boolean add(E e) {
     linkLast(e);
     return true;
}

void linkLast(E e) {
     final Node<E> l = last;
     final Node<E> newNode = new Node<>(l, e, null);
     last = newNode;
     if (l == null)
         first = newNode;
     else
         l.next = newNode;
     size++;
     modCount++;
}

使用这个内部类和这些字段:

private static class Node<E> {
     E item;
     Node<E> next;
     Node<E> prev;

     Node(Node<E> prev, E element, Node<E> next) {
         this.item = element;
         this.next = next;
         this.prev = prev;
     }
 }

Node<E> first, last;

在范围结束后,list没有引用,因此可以收集它。但是,从两个Node调用创建的两个linkLast()每个都有两个引用 - 第一个来自firstlast.prev,第二个来自last {1}}和first.next。收集list只会为每个对象删除其中一个引用,留下一个循环。