任何未使用的对象可以从垃圾收集器中逃脱吗?

时间:2010-01-25 19:44:36

标签: java garbage-collection

是否有任何可能没有在任何地方引用并且仍然存在于堆上的对象。我的意思是,有一个未使用的对象有可能从垃圾收集器中转义并在堆上直到应用程序结束。

想要知道,因为如果它在那里,那么在编码时我可以更加谨慎。

11 个答案:

答案 0 :(得分:7)

如果一个对象不再被引用,它仍然存在于堆上,但它也可以自由地被垃圾收集(除非我们正在谈论Class对象,它们存在于PermGen空间中并且永远不会被垃圾收集 - 但是这通常不是你需要担心的事情。)

无法保证会有多快,但在回收这些对象的内存之前,您的应用程序不会耗尽内存。

但是,垃圾收集确实涉及开销,因此如果您创建的对象超出了您的需求,并且可以轻松创建更少的对象,那么请务必这样做。

编辑:为了回应你的评论,如果某个对象确实没有被任何东西引用,它将在垃圾收集期间回收(假设你使用的是Sun的最新JVM;我不能说到其他实施)。原因如下:所有对象都在堆上连续分配。当GC要发生时,JVM会跟随对它知道可以访问的“标记”对象的所有引用 - 然后将这些对象移动到另一个干净的区域。旧区域被认为是空闲记忆。通过引用无法找到的任何内容都无法移动。关键是GC不需要“找到”未引用的对象。如果有的话,我会更担心在它们不打算时仍然被引用的对象,这将导致内存泄漏。

答案 1 :(得分:6)

你应该知道,在JVM抛出一个内存不足的异常之前,它会收集所有可能的垃圾。

答案 2 :(得分:2)

取决于对象的使用时间和频率。如果你分配一些东西然后解除分配(即删除对它的所有引用),它会立即停留在堆的“新”部分,并可能在下一次垃圾收集运行时被淘汰。

如果在程序开头分配一个对象并保持一段时间(如果它通过几个垃圾收集存活),它将被提升为“旧”状态。堆的该部分中的对象不太可能在以后收集。

如果您想了解所有细节,请查看Sun的一些gc documentation

答案 3 :(得分:2)

如果不再引用实例,则它可能是垃圾收集的候选者。这意味着,迟早它可以被删除,但没有保证。如果你没有内存不足,垃圾收集器可能甚至都没有运行,因此实例我会在那里直到程序结束。

CG系统非常擅长查找未引用的对象。有一个很小的机会,你最终保持一个奇怪的引用混合,垃圾收集器无法确定是否不再引用该对象。但这将是CG系统中的一个错误,在编码时你不应该担心。

答案 4 :(得分:1)

是;想象这样的事情:

Foo foo = new Foo();

// do some work here

while(1) {};

foo.someOp(); // if this is the only reference to foo,
// it's theoreticaly impossible to reach here, so it
// should be GC-ed, but all GC systems I know of will
// not Gc it

我使用的定义是:在任何代码执行中永远无法访问的对象。

答案 5 :(得分:1)

垃圾收集故意无法保证收集对象的时间。如果内存永远不会太紧,那么在程序结束时,完全有可能不会收集未引用的对象。

答案 6 :(得分:1)

垃圾收集器最终会回收所有无法访问的对象。注意“最终”:这可能需要一些时间。你可以用System.gc()来解决这个问题,但这很少是一个好主意(如果没有自行决定使用,那么性能可能会降低)。

可能发生的是一个对象是“未使用”(如:应用程序将不再使用它),同时仍然是“可访问的”(GC可以从其中一个根源找到引用路径 - 静态字段,局部变量 - 对象)。如果你的物体和结构不是太乱,那么你就不会遇到这种情况。一个经验法则是:如果应用程序似乎需要占用太多内存,请在其上运行一个分析器;如果在没有任何明显原因的情况下累积了数千个同一类的实例,那么某处可能会有一些可疑的代码。更正通常涉及将字段显式设置为null以避免引用对象太长时间。

答案 7 :(得分:0)

这在理论上是可行的(不能保证GC总能找到所有对象),但不要担心任何真正的应用程序 - 它通常不会发生,当然也不会影响大量内存。

答案 8 :(得分:0)

理论上,垃圾收集器将找到所有未使用的对象。当然,垃圾收集器中可能存在错误......

那就是说,“从理论上讲,理论与实践没有区别,在实践中也存在差异。”在一些(主要是较旧的)垃圾收集器下,如果对象定义设法到达永久代,那么在任何情况下它将不再被垃圾收集。这仅适用于已加载的类定义,而不适用于已授予终身状态的常规对象。

相应地,如果你有一个对象的静态引用,占用“常规”对象堆中的空间,这可能会导致问题,因为你只需要从类定义中保存对类定义的引用,并且即使您实际上没有引用类本身的任何实例,也不能对静态数据进行垃圾回收。

在实践中,这是一个非常不可能的事件,你不必担心它。如果你非常关注性能,那么创建大量“长期存在”的对象,即逃避“逃逸分析”的对象,将为垃圾收集器创造额外的工作。对于99.99%的编码员来说,这完全没有问题。

答案 9 :(得分:0)

我的建议 - 不要担心。

原因 - 非引用对象可能会在堆上停留一段时间,但它不太可能对您产生负面影响,因为它可以保证在出现内存不足错误之前回收。

答案 10 :(得分:0)

通常,没有实时硬引用的所有对象都将被垃圾收集。这是你应该假设和编码的。但是,这种情况发生的确切时刻是不可预测的。

为了完整,我想到了两个棘手的情况[你不太可能遇到]:

  • JVM中的错误或垃圾收集器代码
  • 所谓的invisible references - 它们很少有用,但在过去的5年里,我确实需要在我工作的性能敏感应用程序中将它们考虑一两次