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

发布于 2024-12-25 14:30:33 字数 159 浏览 3 评论 0原文

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

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

Java 的垃圾收集器是否有任何我忽略的巨大优势?

谢谢

I have always wondered why the garbage collector in Java activates whenever it feels like it rather than do:

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

Are there any big advantages to how Java does it that I overlooked?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

山有枢 2025-01-01 14:30:33

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

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

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

要比较垃圾收集技术,并快速概述 HotSpot 中 GC 的工作原理,您可能需要查看 这些讲座幻灯片来自我上次教授的编译器课程 夏天。您可能还想查看HotSpot 垃圾收集白皮书 更详细地介绍了垃圾收集器的工作原理,包括根据应用程序调整收集器的方法。

希望这有帮助!

Each JVM is different, but the HotSpot JVM does not primarily rely on reference counting as a means for garbage collection. Reference counting has the advantage of being simple to implement, but it is inherently error-prone. In particular, if you have a reference cycle (a set of objects that all refer to one another in a cycle), then reference counting will not correctly reclaim those objects because they all have nonzero reference count. This forces you to use an auxiliary garbage collector from time to time, which tends to be slower (Mozilla Firefox had this exact problem, and IIRC their solution was to add in a garbage collector on top of reference counting). This is why, for example, languages like C++ tend to have a combination of shared_ptrs that use reference counting and weak_ptrs that don't use reference cycles.

Additionally, associating a reference count with each object makes the cost of assigning a reference greater than normal, because of the extra bookkeeping involved of adjusting the reference count (which only gets worse in the presence of multithreading). Furthermore, using reference counting precludes the use of certain types fast of memory allocators, which can be a problem. It also tends to lead to heap fragmentation in its naive form, since objects are scattered through memory rather than tightly-packed, decreasing allocation times and causing poor locality.

The HotSpot JVM uses a variety of different techniques to do garbage collection, but its primary garbage collector is called a stop-and-copy collector. This collector works by allocating objects contiguously in memory next to one another, and allows for extremely fast (one or two assembly instructions) allocation of new objects. When space runs out, all of the new objects are GC'ed simultaneously, which usually kills off most of the new objects that were constructed. As a result, the GC is much faster than a typically reference-counting implementation, and ends up having better locality and better performance.

For a comparison of techniques in garbage collecting, along with a quick overview of how the GC in HotSpot works, you may want to check out these lecture slides from a compilers course that I taught last summer. You may also want to look at the HotSpot garbage collection white paper that goes into much more detail about how the garbage collector works, including ways of tuning the collector on an application-by-application basis.

Hope this helps!

ゝ偶尔ゞ 2025-01-01 14:30:33

引用计数有以下限制:

  • 它对于多线程性能来说非常糟糕(基本上,对象引用的每个分配都必须受到保护)。
  • 您无法自动释放周期

Reference counting has the following limitations:

  • It is VERY bad for multithreading performance (basically, every assignment of an object reference must be protected).
  • You cannot free cycles automatically
ペ泪落弦音 2025-01-01 14:30:33

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

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

例如:

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 在编译过程中提前处理这些事情,并且本身不需要特定的运行时),因此绝对可以按照与您描述的方式类似的方式完成,但是它只是不适用于某些功能爪哇。我还相信 COM 的工作方式与您所描述的方式更相似...但同样,这并不是没有开发人员方面的一些考虑。

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

Because it doesn't work strictly based on reference counting.

Consider circular references which are no longer reachable from the "root" of the application.

For example:

APP has a reference to SOME_SCREEN

SOME_SCREEN has a reference to SOME_CHILD

SOME_CHILD has a reference to SOME_SCREEN

now, APP drops it's reference to SOME_SCREEN.

In this case, SOME_SCREEN still has a reference to SOME_CHILD, and SOME_CHILD still has a reference to SOME_SCREEN - so, in this case, your example doesn't work.

Now, others (Apple with ARC, Microsoft with COM, many others) have solutions for this and work more similarly to how you describe it.

With ARC you have to annotate your references with keywords like strong and weak to let ARC know how to deal with these references (and avoid circular references)... (don't read too far into my specific example with ARC because ARC handles these things ahead-of-time during the compilation process and doesn't require a specific runtime per-se) so it can definitely be done similarly to how you describe it, but it's just not workable with some of the features of Java. I also believe COM works more similarly to how you describe... but again, that's not free of some amount of consideration on the developer's part.

In fact, no "simple" reference counting scheme would ever be workable without some amount of thought by the application developer (to avoid circular references, etc)

秉烛思 2025-01-01 14:30:33

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

Because the garbage collector in modern JVMs is no longer tracking references count. This algorithm is used to teach how GC works, but it was both resource-consuming and error-prone (e.g. cyclic dependencies).

星星的轨迹 2025-01-01 14:30:33

因为java中的垃圾收集器是基于“年轻一代”对象的复制收集器,并且
标记并清理“tenure Generations”对象。

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

because the garbage collector in java is based on copying collector for 'youg generation' objects, and
mark and sweep for `tenure generations' objects.

Resources from: http://java.sun.com/docs/hotspot/gc1.4.2/faq.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文