9

在我正在修改的幻灯片上,它说以下内容:

可以通过维护对每个对象的引用数的计数,或通过跟踪从根开始的引用链来识别活动对象。

引用计数很昂贵——每次引用发生变化时都需要采取行动,而且它不会发现循环结构,但它可以逐步回收空间。

跟踪涉及仅在需要回收空间时识别活动对象——将成本从一般访问转移到 GC 运行时间,通常仅在内存不足时。

我理解为什么引用计数很昂贵的原理,但不明白什么是“不能发现循环结构,但它可以逐步回收空间”。方法。任何人都可以帮我一点吗?

谢谢

4

5 回答 5

5

引用计数没有发现周期性结构......

假设您有两个对象 O1 和 O2。它们相互引用:O1 -> O2 和 O2 -> O1,并且没有其他对象引用它们。它们都将具有引用计数 1(一个引用者)。

如果 O1 或 O2 都无法从 GC 根访问,则可以安全地对它们进行垃圾收集。但是,这并不能通过计数引用来检测,因为它们的引用计数 > 0。

0 引用是对象符合垃圾回收条件的充分但非必要要求。

...但它可以逐步回收空间。

增量部分是指您可以快速垃圾收集一些 0 引用的对象,被中断并在另一个时间继续而不会出现问题。

如果跟踪算法被中断,它将需要在下一次调度时从头开始。(参考树可能从一开始就发生了变化!)

于 2010-05-31T10:12:56.153 回答
1
  1. 简单的引用计数无法解决 A 引用 B 和 B 引用 A 的情况。在这种情况下,A 和 B 的引用计数都为 1,即使没有其他引用也不会被收集。
  2. 当某个对象的引用计数器变为0时,引用计数可以立即回收空间。不需要等待GC周期,扫描其他对象等。因此,从某种意义上说,它是递增地从对象中回收空间的。
于 2010-05-31T10:13:24.623 回答
1

“没有发现周期性结构”

假设我有一个对象AA需要另一个被调用的对象B来完成它的工作。但是B需要调用另一个对象C来完成它的工作。但出于某种原因C需要一个指向的指针。A所以依赖图看起来像:

A -> B -> C -> A

对象的引用计数应该是指向它的箭头的数量。在这个例子中,每个对象都有一个引用计数。

假设我们的主程序在执行过程中创建了一个这样的结构,并且主程序有一个指向 的指针A,使A' 的计数等于 2。当这个结构超出范围时会发生什么?A的引用计数减一。

但请注意!现在A,BC所有的引用计数都是 1 ,即使它们无法从主程序访问。所以这是内存泄漏。维基百科有关于如何解决这个问题的详细信息。

“它可以逐步回收空间”

大多数垃圾收集器都有一个收集周期,在此期间它们会暂停执行并释放不再使用的对象。在标记和扫描系统中,这是扫描步骤。不利的一面是,在两次扫描之间的时间段内,内存不断增长。一个对象可能在创建后几乎立即停止使用,但在下一次扫描之前它永远不会被回收。

在引用计数系统中,对象的引用计数一达到零就会被释放。没有大的停顿或任何大的扫描步骤,不再使用的对象不会只是坐在那里等待收集,它们会立即被释放。因此,收集是增量的,因为它增量收集不再使用的任何对象,而不是批量收集自上次收集以来已不再使用的所有对象。

Of course, this incrementalism may come with its own pitfalls, namely that it might be less expensive to do a bulk GC rather than a lot of little ones, but that is determined by the exact implementation.

于 2010-05-31T10:19:33.730 回答
0

假设您有三个对象(A、B、C):A 对 B 有引用,B 对 C 有引用,C 对 A 有引用。但没有其他对象对其中一个有任何引用。是一个独立的循环结构。使用传统的引用计数会阻止垃圾收集器删除循环,因为每个对象仍然被引用。但只要没有人对这三个中的一个有参考,他们就可以/应该被删除。我猜想增量回收空间意味着在查找未引用实例、无循环等时引用计数的工作方式。

于 2010-05-31T10:14:01.580 回答
0

如果引用计数达到 0,则可以释放对象以进行垃圾收集。

对于循环引用,这永远不会发生,因为圆中的每个对象都保持对另一个对象的引用,因此它们都至少为 1。

为此,需要一些图论来检测不再附加到任何东西的引用,比如堆海中的小岛。为了将它们保存在内存中,它们必须在某处对静态变量有一些“附件”。

这就是追踪的作用。它确定堆的哪些部分是孤岛并且可以被释放,哪些仍然连接到大陆,即静态变量smewhere。

于 2010-05-31T10:16:12.000 回答