为什么 JVM 不会在引用计数达到 0 时立即销毁资源?



我一直在想,为什么Java中的垃圾收集器会在任何时候激活,而不是激活:

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

Java有什么我忽略的优点吗?

感谢

每个JVM都不同,但HotSpot JVM并不主要依赖引用计数作为垃圾收集的手段。参考计数具有实现简单的优点,但它本身就容易出错。特别是,如果有一个引用循环(一组在循环中相互引用的对象),则引用计数将无法正确回收这些对象,因为它们的引用计数都为非零。这迫使你不时地使用辅助垃圾收集器,这往往会更慢(Mozilla Firefox就有这个问题,IIRC的解决方案是在引用计数的基础上添加一个垃圾收集器)。这就是为什么,例如,像C++这样的语言倾向于使用引用计数的shared_ptr和不使用引用循环的weak_ptr的组合。

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

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

为了比较垃圾收集技术,以及快速概述HotSpot中GC的工作原理,您可能想查看这些来自我去年夏天教的编译器课程的讲座幻灯片。您可能还想查看HotSpot垃圾收集白皮书,该白皮书详细介绍了垃圾收集器的工作方式,包括在逐个应用程序的基础上调整收集器的方法。

希望这能有所帮助!

参考计数有以下限制:

  • 它对多线程性能非常不利(基本上,对象引用的每个赋值都必须受到保护)
  • 不能自动释放循环

因为它不能严格根据引用计数工作。

考虑不再可以从应用程序的"根"访问的循环引用。

例如:

APP引用了SOME_SCREEN

SOME_SCREEN引用了SOME_CHILD

SOME_CHILD引用了SOME_SCREEN

现在,APP放弃了对SOME_SCREEN的引用。

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

现在,其他公司(苹果和ARC,微软和COM,许多其他公司)都有解决方案,并且工作方式与你描述的更相似

使用ARC,您必须用strongweak等关键字注释引用,让ARC知道如何处理这些引用(并避免循环引用)。。。(不要读太多关于ARC的具体例子,因为ARC在编译过程中提前处理这些事情,本身不需要特定的运行时),所以它肯定可以像描述它一样完成,但它与Java的一些功能不兼容。我也相信COM的工作原理与你描述的更相似。。。但同样,这也并非没有开发者的考虑。

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

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

因为java中的垃圾收集器是基于"youg generation"对象的copying collector,并且"保有权生成"对象的mark and sweep

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

最新更新