简体   繁体   English

什么时候对象符合垃圾收集条件?

[英]When Is The Object Eligible For Garbage Collection?

In the code below, given that amethod has been called. 在下面的代码中,假设已经调用了amethod At what point/line is the Object originally referenced by myObject , eligible for Garbage Collection? 在什么点/行是myObject最初引用的对象,有资格获得垃圾收集?

class Test {
  private Object classObject;

  public void amethod() {
    Object myObject = new Object();
    classObject = myObject;
    myObject = null;
  }
}

And if classObject or amethod had an access modifier of public, protected, default or static, would it affect what point the Object is eligible for Garbage Collection? 如果classObjectamethod具有public,protected,default或static的访问修饰符,它会影响Object符合垃圾收集的条件吗? If so, how would it be affected? 如果是这样,它将如何受到影响?

  • My first thought is that the Object is eligible for Garbage Collection when the Test object is eligible for Garbage Collection. 我首先想到的是,当Test对象符合垃圾收集条件时,Object符合垃圾收集条件。
  • But then again. 但话又说回来。 The optimizer may know that the classObject is never read from in which case classObject = myObject; 优化器可能知道从不读取classObject,在这种情况下classObject = myObject; would be optimized out and myObject = null; 将被优化出来并且myObject = null; is the point it is eligible for Garbage Collection. 是它有资格获得垃圾收集的点。

The object will not become a candidate for garbage collection until all references to it are discarded. 在丢弃对它的所有引用之前,该对象不会成为垃圾收集的候选对象。 Java objects are assigned by reference so when you had Java对象是通过引用分配的,所以当你有

   classObject = myObject;

You assigned another reference to the same object on the heap. 您为堆上的同一对象分配了另一个引用。 So this line 所以这一行

   myObject = null;

Only gets rid of one reference. 只删除一个引用。 To make myObject a candidate for garbage collection, you have to have 要使myObject成为垃圾收集的候选者,您必须拥有

  classObject = null;

This is actually addressed precisely by the Java Language Specification, §12.6.1, Implementing Finalization : 这实际上是通过Java语言规范§12.6.1,实现完成来实现的

Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. 可以设计优化程序的转换,以减少可达到的对象的数量,使其少于可以被认为可达的对象的数量。 For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner. 例如,Java编译器或代码生成器可以选择设置将不再用于null的变量或参数,以使得此类对象的存储可能更快地被回收。

Another example of this occurs if the values in an object's fields are stored in registers. 如果对象字段中的值存储在寄存器中,则会出现另一个示例。 The program may then access the registers instead of the object, and never access the object again. 然后程序可以访问寄存器而不是对象,并且永远不会再次访问对象。 This would imply that the object is garbage. 这意味着该对象是垃圾。 ...

But

… Note that this sort of optimization is only allowed if references are on the stack, not stored in the heap. ...请注意,只有在引用位于堆栈上且未存储在堆中时,才允许进行此类优化。

For example, consider the Finalizer Guardian pattern: 例如,考虑Finalizer Guardian模式:

  class Foo { private final Object finalizerGuardian = new Object() { protected void finalize() throws Throwable { /* finalize outer Foo object */ } } } 

The finalizer guardian forces super.finalize to be called if a subclass overrides finalize and does not explicitly call super.finalize . 终结监护人力super.finalize如果子类重写被称为finalize ,不显式调用super.finalize

If these optimizations are allowed for references that are stored on the heap, then a Java compiler can detect that the finalizerGuardian field is never read, null it out, collect the object immediately, and call the finalizer early. 如果允许对存储在堆上的引用进行这些优化,那么Java编译器可以检测到finalizerGuardian字段永远不会被读取,将其清空,立即收集对象,并尽早调用终结器。 This runs counter to the intent: the programmer probably wanted to call the Foo finalizer when the Foo instance became unreachable. 这与意图背道而驰:程序员可能希望在Foo实例无法访问时调用Foo终结器。 This sort of transformation is therefore not legal: the inner class object should be reachable for as long as the outer class object is reachable. 因此,这种转换不合法:只要外部类对象可以访问,内部类对象就应该可以访问。

This example can be applied 1:1 to your example, as long as the object is referenced by the instance field classObject , it can not get garbage collected earlier than the Test instance containing the reference. 此示例可以1:1应用于您的示例,只要该对象由实例字段classObject ,它就不能比包含引用的Test实例更早地收集垃圾。

Note, however, that the aggressive optimizations mentioned in the specification are still allowed, when being applied to the code using the Test instance. 但请注意,当使用Test实例应用于代码时,仍然允许规范中提到的积极优化。 The earlier-than-expected collection may happen, as long as both , the Test instance and the referenced object are collected together. 只要两者同时收集Test实例和引用的对象,就可能发生早于预期的收集。 In this case, the following aspect specified in §12.6 applies: 在这种情况下, §12.6中规定的以下方面适用:

The Java programming language imposes no ordering on finalize method calls. Java编程语言对finalize方法调用没有任何排序。 Finalizers may be called in any order, or even concurrently. 终结器可以按任何顺序调用,甚至可以同时调用。

So it's perfectly possible that the Test instance is collected earlier than the object referenced by classObject whereas the “inner” object's finalizer is invoked earlier. 因此,完全有可能早于classObject引用的对象收集Test实例,而之前调用“inner”对象的终结器。 The only thing that is guaranteed, is, that when the inner object's finalizer runs, the outer object is unreachable (or has a pending or concurrent finalization). 唯一可以保证的是,当内部对象的终结器运行时,外部对象无法访问(或者具有挂起或并发终结)。 Since in your example, neither has a non-trivial finalizer, that doesn't matter anyway… 因为在你的例子中,既没有非平凡的终结器,也无论如何......

Your idea that the private object may be GC'd right away because no other code is able to access it does have some traction, but this would mess with the general semantics of Java memory management. 你的想法是私有对象可能立即被GC,因为没有其他代码能够访问它确实有一些牵引力,但这会混淆Java内存管理的一般语义。 For example, if that object implemented finalize , and Java semantics clearly dictates when an object is eligible for garbage collection, that finalizer method would be have to be called against the specification. 例如,如果该对象实现了finalize ,并且Java语义明确规定何时对象符合垃圾收集条件,那么必须根据规范调用终结器方法。

Also note that the object in turn may reference other objects, with even more complicated possible outcomes. 另请注意,对象反过来可能会引用其他对象,甚至可能会产生更复杂的结果。 Not to mention the object is reachable by Reflection anytime and it would make no sense for the field to be observed to suddenly change to null even if no code could have made that assignment. 更不用说随时可以通过Reflection访问该对象,即使没有代码可以进行该分配,观察到的字段突然变为null也没有任何意义。

To conclude, there are many reasons why your idea of optimization would not work in the wider picture. 总而言之,有很多原因可以解释为什么你的优化思想不能在更广泛的范围内发挥作用。

From Book OCA Java SE 7 来自Book OCA Java SE 7

An object is marked as eligible to be garbage collected when it can no longer be accessed, which can happen when the object goes out of scope. 当对象无法再访问时,该对象被标记为有资格进行垃圾回收,这可能在对象超出范围时发生。 It can also happen when an object's reference variable is assigned an explicit null value or is reinitialized. 当对象的引用变量被赋值为显式空值或被重新初始化时,也会发生这种情况。

这里没有对象符合垃圾回收的条件,因为您要为同一个对象创建两个引用,并且只给一个引用赋予null,但是其他引用仍指向对象

由于您在classObject中保存myObject引用被维护 ),因此在释放/卸载Test实例之前,它(通过classObject引用的内存中的对象)将无法用于垃圾收集。

In the code below, given that amethod has been called. 在下面的代码中,假设已经调用了amethod。 At what point/line is the Object originally referenced by myObject, eligible for Garbage Collection? 在什么点/行是myObject最初引用的对象,有资格获得垃圾收集?

Your question is nonsensical because there is a disconnect between your high-level source code and the low-level representation (global roots in registers, on the stack and in global variables) that the garbage collector sees. 您的问题是荒谬的,因为您的高级源代码与垃圾收集器看到的低级表示(寄存器,堆栈和全局变量中的全局根)之间存在脱节。

Your phrase "eligible for garbage collection" presumably means at what point does a heap-allocated block of memory become unreachable. 你的短语“有资格进行垃圾收集”可能意味着堆分配的内存块在什么时候无法访问。 So your question can only be answered by making a lot of (dubious) assumptions about what heap allocates and how long the generated code will keep references. 因此,您的问题只能通过对堆分配的内容以及生成的代码保留引用的时间做出很多(可疑的)假设来回答。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM