为什么JVM无法确保垃圾回收

jav*_*ped 0 java garbage-collection

这不是重复,因为提到重复的线程只告诉你为什么不使用System.gc(),而我知道,这不是我的问题.

使用System.gc()或Runtime.getRuntime().gc()并不总是执行垃圾收集,它只是请求它,它甚至可以被JVM忽略.

这背后有原因吗?它是"随机的"吗?由于我不认为随机甚至存在于编程中,我很好奇它为什么有时不收集它,有时也会在不同的时间收集它.

Ste*_*n C 8

是.有一个很好的理由.


首先,您需要了解有关垃圾收集的一些事实:

  1. 运行垃圾收集器很昂贵.
  2. 在错误的时间(重复)运行垃圾收集器可能会造成灾难性的低效1.
  3. 接下来,典型应用程序无法预测GC何时可以最有效地运行.

所以对你的问题:

使用System.gc()或Runtime.getRuntime().gc()并不总是执行垃圾收集,它只是请求它,它甚至可以被JVM忽略.这背后有原因吗?

是.它主要是为了防止天真的程序员gc()在错误的时间调用可能造成的灾难性行为影响.

它是"随机的"吗?

不.它与随机性无关.

实际上,典型的JVM有一个命令行开关,用于确定是否gc()忽略调用.这允许用户/部署者/集成商/任何人减轻程序员做出的糟糕选择.

但请注意,它无法从Java代码中重写.这会破坏使其成为命令行开关的目的.

我很好奇为什么它有时不会收集它,有时也会在不同的时间收集它.

JVM的正常行为是在最有效的情况下尝试运行垃圾收集器.JVM可以优化两种方式:

  • 它可以优化以最大化收集器的吞吐量; 即最小化在收集上花费的CPU时间

  • 它可以优化以最小化GC暂停的长度; 即JVM在收集期间必须冻结所有应用程序线程的时间.

这很复杂.从外部观察者(谁/无法访问堆统计数据等)的角度来看,可能很难理解为什么GC在给定时间点运行.但肯定不是随意的.


1 - GC算法的一个反直觉属性是收集成本(在大多数情况下)由跟踪非垃圾对象和在内存中移动以合并释放空间的成本支配.因此,如果在没有太多垃圾收集的情况下调用GC,您将最终跟踪/移动大量非垃圾,实际上没什么好处.相比之下,JVM可以更好地了解何时是收集的好时机.首先,它知道在任何时间点每个池中剩余多少空间.

除了反直觉之外,随着堆变大,这种行为也会变得更糟.因此,程序员可以编写gc()以错误方式使用的代码,而不会注意到存在性能问题.当应用程序以生产工作负载/问题大小运行时,性能只会成为问题.将此与使用堆缓存内容和/或内存泄漏的效果相结合.....