这种技术会防止Java进行垃圾回收吗?

3

Colt McAnlis在如何防止JavaScript垃圾回收器减慢应用程序方面做了一个非常有趣的视频(链接)

要点如下:

  1. 当应用程序加载时,实例化一组未使用的对象/类,这些对象/类将来可能需要使用。
  2. 当您想要实例化一个新对象时,而不是创建新的对象,请从池中找到一个合适类型的未使用的对象,获取它并设置其属性。
  3. 以后可以使用此对象。
  4. 完成后,请将其标记为“未使用”,以便以后的方法可以使用它。

我的问题是,如果这种方法也适用于Java垃圾回收器,或者是否更难绕过它,只会扫描整个堆之类的东西。

这主要是一个理论上的/好奇心问题。我没有任何依赖于规避垃圾回收的开发中的应用程序。


只要您仍然拥有对象的引用,它们就不符合垃圾回收的条件。 - khelwood
2
Effective Java中有一些关于使用对象池的内容。JVM在内存管理方面通常比您更优秀。 - Andy Turner
1个回答

4
它在某种意义上“可行”,但不建议使用,因为存在一些重大问题。
  1. 如果实现不正确,它就是内存泄漏。问题在于“池”需要保留对其所有对象的引用。这会阻止它们被垃圾回收。但是,如果应用程序在完成对象时未始终将对象标记为“未使用”(例如,一个错误),则这些对象将永久保持“正在使用”状态。

    (如果尝试使用类似Reference对象之类的东西来缓解此问题,您将使用更多空间,并增加GC的负担。)

  2. 当GC运行时,它必须遍历池中的所有对象以及它们的依赖对象。这要比对象允许死亡更费力。(年轻的不可达对象根本不需要扫描。)

  3. 几次GC周期后,池中的对象将被tenured,因为它们具有长寿命。这意味着它们倾向于导致可能本可以被收集的短期相关对象被保留,直到收集旧堆。此外,分配给tenured对象字段的引用可能更昂贵,并且可能使young space collection时间变长(因为老-> young references)。

请注意,您正在讨论的对象池类型通常是为了减轻应用程序中过多GC暂停而提出/完成的。在典型的现代JVM中,有专门设计以最小化暂停的GC。对于大多数Java应用程序来说,低暂停收集器是解决这个问题的更好选择。(例外是高度交互式游戏,任何“滞后”都是不可接受的。)

使用对象池的其他原因:

  • 处理初始化非常昂贵的对象。
  • 处理需要限制数量的对象。
  • 处理与需要正确管理的外部资源相关联的对象。

例如线程池、数据库连接池和HTTP连接池(在典型的HTTP客户端库下)。在适当的情况下,这些绝对是有益的。


1
作为对@Stephen出色回答的补充,我想要补充一点(仅为完整性),对于某些类来说,对象池是正确的选择。典型的例子是JDBC实例和线程。它们的特点是创建成本高昂。 - Erik
已经解决了这个问题。(昂贵的创建是其中一个特征。) - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接