【问题标题】:What are the practical examples of reference cycles?参考循环的实际例子有哪些?
【发布时间】:2018-07-21 16:30:49
【问题描述】:

垃圾收集器具有处理引用循环的功能。据我了解,这对于所有带有 GC 的语言都是必要的。

但我不明白,为什么不能创建语言避免引用循环,必要时使用一些弱引用。

在编程中不可避免的引用循环的真实例子有哪些?

【问题讨论】:

  • 我们制作引用循环的原因并不是因为无法避免它们。我们制定参考循环是因为避免它们有时是困难的、低效的、不优雅的或其他不可取的。
  • @user2357112 你能提供任何常见的例子吗,避免它会效率低下或不受欢迎?

标签: reference garbage-collection


【解决方案1】:

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

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

 ┌──────┐             ┌──────┐             ┌──────┐             ┌──────┐             
 │      │ -next-----> │      │ -next-----> │      │ -next-----> │      │
 │ Node │             │ Node │             │ Node │             │ Node │
 │      │ <-previous- │      │ <-previous- │      │ <-previous- │      │
 └──────┘             └──────┘             └──────┘             └──────┘

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

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

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

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

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


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

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

【讨论】:

    【解决方案2】:

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

    在一个不太抽象的注释上,graphs have many practical uses。基本上,它们代表物联网:Facebook 上的朋友网络、地图上的城市网络、互联网上的计算机网络等。

    【讨论】:

      【解决方案3】:

      我认为这个问题实际上与 Rust 中的所有权系统密切相关。然后我首先想到了这个问题,事实证明,我有点类似于 Rust 范围规则。

      所以@Holger 给出了一个双链表的例子,where is an entire book 关于 Rust 中的此类列表。我想它可能会对这个问题有所启发。

      【讨论】:

        猜你喜欢
        • 2014-12-30
        • 2019-12-24
        • 1970-01-01
        • 2023-04-10
        • 2011-06-06
        • 2019-02-13
        • 1970-01-01
        • 2011-11-19
        • 2012-02-29
        相关资源
        最近更新 更多