这可能是理论上的一点,我需要这个,因为我正在设计我自己的编程语言,作为一个爱好项目的乐趣。我认为记忆管理是“四代”。这是我自己的看法,与任何纸张或学校无关。
第一代是平坦的内存块,应用程序只管理它如何。
第二代是malloc / free style heap。系统将处理内存,但您处理对象。
第三代是引用计数分配/处置,它在“到位”或换句话说在调用new / delete期间发生。
第四代是你通常所说的垃圾收集器。在调用新/删除或其他过程期间,可能会发生在另一个线程中或有时像第三代一样的事情。
主要区别在于第4代GC有时会“走”或“扫描”堆对象,并检查其中一些是否“无根”,以便它可以删除tham。这是非常复杂的,有许多算法用于“扫描”。有时这些算法名称中有一个“颜色”字样。像“三色标记”或“三色计数异步并行”等。进行“堆扫描”的最明显原因是处理循环引用。因为没有(还有?)其他方式来处理它。
现在回答我的问题。
如果没有第4代GC,那么圆形参考的“真实生活”例子是什么?当然你可以输入两行代码,故意创建循环引用。但这不是我的问题。我想要一个“真实”的例子,我的意思是可以自然发生的事情,并且可以很容易理解。对于任何一个新的东西,你可以真正地展示出你需要用GC处理的循环引用。也许我也可以使用“实用”和“有用”的词语来描述这样的例子。
答案 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()
每个都有两个引用 - 第一个来自first
和last.prev
,第二个来自last
{1}}和first.next
。收集list
只会为每个对象删除其中一个引用,留下一个循环。