参考周期的实际例子是什么?

uhb*_*f19 6 garbage-collection reference

垃圾收集器具有处理参考周期的功能.到目前为止,据我所知,这对于所有使用GC的语言都是必要的.

但我不明白,为什么不能创建语言避免参考周期,必要时使用一些弱引用.

在编程中出现的不可避免的参考周期的实际例子是什么?

Hol*_*ger 5

您不能创建一种避免引用循环的编程语言,因为应用程序员有责任而不是创建循环。您只能创建一种要求程序员始终承担该责任的语言。

这是数据结构的基本设计,可能允许或不允许循环。例如,在 Java 中,aList是一个引用列表,因此List,直接或间接存储 a本身没有问题。但是举一个更直接的例子,对于双向链表,每个节点都有一个指向它的下一个节点和它的前一个节点的指针。这已经足以形成参考循环:

 ????????             ????????             ????????             ????????             
 ?      ? -next-----> ?      ? -next-----> ?      ? -next-----> ?      ?
 ? Node ?             ? Node ?             ? Node ?             ? Node ?
 ?      ? <-previous- ?      ? <-previous- ?      ? <-previous- ?      ?
 ????????             ????????             ????????             ????????
Run Code Online (Sandbox Code Playgroud)

这已经形成了多个循环,两个相邻节点之间通过它们的previousnext引用形成了短循环,但也间接地在其他节点之间形成了循环。

为了通过弱引用切断这些循环,Node类的设计者必须决定是否使nextprevious引用变弱。它们中的任何一个都会破坏其中一个基本功能:

  • 如果您有对第一个节点的引用,则可以通过next引用链到达并遍历所有节点
  • 如果您有对最后一个节点的引用,则可以通过previous引用链到达并遍历所有节点
  • 事实上,引用任何链接的节点就足以到达所有节点
  • 如果所有节点都无法访问,则所有节点都可以进行垃圾收集

如果您将两个引用中的一个声明为弱引用,则不能假设对一个节点的引用使所有节点都保持活动状态。如果next弱,则需要始终保留对最后一个节点的引用,以防止突然删除下一个节点。如果previous很弱,则必须始终保持对第一个节点的引用。

因此,要求开发人员始终通过弱引用切断循环会导致对方式的根本限制,因此必须设计软件。再举一个例子,考虑一个注册监听器的组件会在事件发生时修改该组件(或另一个组件引用前者),从而形成一个循环。使侦听器引用变弱意味着它可能会突然无故消失。


也就是说,即使是弱引用本身也是垃圾收集器在进行图遍历时自然提供的一个特性,因为只有那些在发现它们存在时才能廉价地采取行动。当一个引用计数系统发现最后一个/唯一一个现有的强引用被删除时,它可以轻松地释放一个对象,但是当对象被释放时,它需要对所有现有的弱引用进行额外的簿记以清除它们。

这就是引用计数的意义所在。实现起来不再简单(这是唯一的优点),同时效率低下,因为在遍历对象图时,例如遍历链表,您必须永久更新引用计数器(在线程中)如果您的语言支持多线程,这是一种安全的方式),而遍历垃圾收集器仅在必须检查可回收内存时才需要做一些事情。而且它只需要遍历活着的对象,因此它可以无所作为的时间越长,它在下一个循环中的工作就越少。


ent*_*erd 1

编程中的核心数据结构之一是,它只是互连的节点组。图表中完全允许存在循环。由于节点可以编码为堆上的对象,因此循环是必要的。

从不太抽象的角度来说,图表有许多实际用途。基本上,它们代表物联网:Facebook 上的朋友网络、地图上的城市网络、互联网上的计算机网络等。