9

我一直想知道为什么 Java 中的垃圾收集器会在需要时激活而不是激活:

if(obj.refCount == 0)
{
   delete  obj;
}

我忽略了Java如何做它有什么大的优势吗?

谢谢

4

5 回答 5

19

每个 JVM 都不同,但 HotSpot JVM 并不主要依赖引用计数作为垃圾收集的手段。引用计数具有易于实现的优点,但它本质上容易出错。特别是,如果您有一个引用循环(一组在一个循环中相互引用的对象),那么引用计数将不会正确回收这些对象,因为它们都具有非零引用计数。这迫使您不时地使用辅助垃圾收集器,这往往会更慢(Mozilla Firefox 遇到了这个确切的问题,他们的解决方案是以增加代码可读性为代价添加垃圾收集器)。这就是为什么,例如,像 C++ 这样的语言倾向于组合shared_ptr使用引用计数weak_ptr的 s 和不使用引用循环的 s。

此外,将引用计数与每个对象关联会使分配引用的成本高于正常情况,因为调整引用计数涉及额外的簿记(在存在多线程的情况下只会变得更糟)。此外,使用引用计数排除了使用某些类型的快速内存分配器,这可能是一个问题。它还倾向于以幼稚的形式导致堆碎片,因为对象分散在内存中而不是紧密地打包,从而减少了分配时间并导致局部性差。

HotSpot JVM 使用各种不同的技术进行垃圾收集,但它的主要垃圾收集器称为停止和复制收集器。该收集器通过在内存中相邻分配对象来工作,并允许非常快速(一个或两个汇编指令)分配新对象。当空间用完时,所有新对象都会同时被 GC 处理,这通常会杀死大部分已构建的新对象。因此,GC 比典型的引用计数实现要快得多,并且最终具有更好的局部性和更好的性能。

为了比较垃圾收集技术,以及快速了解 HotSpot 中 GC 的工作原理,您可能需要查看我去年夏天教授的编译器课程中的这些讲座幻灯片。您可能还想查看HotSpot 垃圾收集白皮书,其中详细介绍了垃圾收集器的工作原理,包括基于应用程序调整收集器的方法。

希望这可以帮助!

于 2012-01-08T21:26:17.927 回答
4

引用计数有以下限制:

  • 这对多线程性能非常不利(基本上,对象引用的每个分配都必须受到保护)。
  • 您不能自动释放周期
于 2012-01-08T21:25:27.473 回答
2

因为它不能严格基于引用计数来工作。

考虑不再从应用程序的“根”访问的循环引用。

例如:

APP有参考SOME_SCREEN

SOME_SCREEN有参考SOME_CHILD

SOME_CHILD有参考SOME_SCREEN

现在,APP删除它的引用SOME_SCREEN

在这种情况下,SOME_SCREEN仍然有对 的引用SOME_CHILD,并且SOME_CHILD仍然有对SOME_SCREEN- 的引用,因此,在这种情况下,您的示例不起作用。

现在,其他人(Apple 与 ARC,Microsoft 与 COM,还有许多其他人)为此提供了解决方案,并且与您描述它的方式更相似。

使用 ARC,您必须使用关键字等注释您的引用,strongweak让 ARC 知道如何处理这些引用(并避免循环引用)......(不要对我使用 ARC 的具体示例读得太深,因为 ARC 会提前处理这些事情-of-time 在编译过程中并且不需要特定的运行时本身)所以它绝对可以像你描述它的方式一样完成,但它只是不适用于 Java 的某些特性。我也相信 COM 的工作方式与您描述的方式更相似……但同样,开发人员也没有考虑到这一点。

事实上,如果没有应用程序开发人员的一些思考(避免循环引用等),任何“简单”的引用计数方案都不可行

于 2012-01-08T21:24:26.207 回答
0

因为现代 JVM 中的垃圾收集器不再跟踪引用计数。该算法用于教授 GC 的工作原理,但它既耗费资源又容易出错(例如循环依赖)。

于 2012-01-08T21:24:34.077 回答
0

因为Java中的垃圾收集器是基于copying collector“年轻一代”对象和 mark and sweep“终身一代”对象的。

资源来自:http: //java.sun.com/docs/hotspot/gc1.4.2/faq.html

于 2012-01-08T21:26:24.663 回答