[英]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? 如果
classObject
或amethod
具有public,protected,default或static的访问修饰符,它会影响Object符合垃圾收集的条件吗? If so, how would it be affected? 如果是这样,它将如何受到影响?
classObject = myObject;
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 overridesfinalize
and does not explicitly callsuper.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 theFoo
finalizer when theFoo
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.