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

Java 为什么';JVM不会在引用计数达到0时立即销毁资源吗?,java,garbage-collection,reference-counting,Java,Garbage Collection,Reference Counting,我一直在想,为什么Java中的垃圾收集器会在它感觉到的时候激活,而不是激活: if(obj.refCount == 0) { delete obj; } Java是如何做到这一点的,有什么我忽略了的巨大优势吗 谢谢,因为它不能严格根据引用计数工作 考虑从应用程序的“根”处不再可以访问的循环引用 例如: APP引用了SOME\u屏幕 SOME\u屏幕引用了SOME\u子屏幕 SOME\u CHILD引用了SOME\u屏幕 现在,APP删除了对SOME\u屏幕的引用 在本例中,SOME\u

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

if(obj.refCount == 0)
{
   delete  obj;
}
Java是如何做到这一点的,有什么我忽略了的巨大优势吗


谢谢

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

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

例如:

APP
引用了
SOME\u屏幕

SOME\u屏幕
引用了
SOME\u子屏幕

SOME\u CHILD
引用了
SOME\u屏幕

现在,
APP
删除了对
SOME\u屏幕的引用

在本例中,
SOME\u SCREEN
仍然引用
SOME\u CHILD
,而
SOME\u CHILD
仍然引用
SOME\u SCREEN
——因此,在本例中,您的示例不起作用

现在,其他人(苹果和ARC,微软和COM,还有许多其他人)已经有了解决方案,并且工作方式与您描述的更为相似

使用ARC,您必须使用诸如
strong
weak
之类的关键字对引用进行注释,以让ARC知道如何处理这些引用(并避免循环引用)。。。(不要过多地阅读我关于ARC的具体示例,因为ARC在编译过程中提前处理这些事情,并且不需要特定的运行时本身),因此它肯定可以像您描述它的方式那样完成,但它对于Java的一些特性来说是不可行的。我还认为COM的工作原理与您描述的更为相似。。。但同样,这也不能免除开发者的一些考虑


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

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

引用计数有以下限制:

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

每个JVM都不同,但热点JVM主要不依赖引用计数作为垃圾收集的手段。引用计数的优点是易于实现,但它本身就容易出错。特别是,如果您有一个引用循环(一组对象在一个循环中相互引用),那么引用计数将无法正确回收这些对象,因为它们都具有非零引用计数。这迫使您不时地使用一个辅助垃圾收集器,这往往比较慢(Mozilla Firefox就有这个问题,他们的解决方案是以牺牲代码可读性为代价添加一个垃圾收集器)。这就是为什么,C++之类的语言倾向于使用引用计数和<代码>弱pTR < /代码> s的不使用参考循环的 SyddYPPTR>代码> s。 此外,将引用计数与每个对象关联会使分配引用的成本高于正常成本,因为调整引用计数会涉及额外的簿记(在存在多线程的情况下,这只会变得更糟)。此外,使用引用计数排除了使用某些类型的快速内存分配器,这可能是一个问题。由于对象分散在内存中,而不是紧密地打包在一起,因此它往往会导致原始形式的堆碎片,从而减少分配时间并导致局部性差

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

为了比较垃圾收集技术,以及快速概述HotSpot中的GC如何工作,您可能想查看我去年夏天教过的编译器课程。您可能还想看看,其中详细介绍了垃圾收集器的工作原理,包括根据应用程序对收集器进行调优的方法


希望这有帮助

因为java中的垃圾收集器基于“youg generation”对象的
复制收集器
标记并扫描
,用于“保留世代”对象


参考资料来源:

我认为任何主流JVM都没有使用过引用计数。+1还值得一提的是,多线程程序的原子计数器缓冲甚至更昂贵。如果不提及GC暂停,关于这一点的讨论就不完整了。