简体   繁体   English

Java中的垃圾收集器-将对象设置为null

[英]Garbage collector in java - set an object null

Lets assume, there is a Tree object, with a root TreeNode object, and each TreeNode has leftNode and rightNode objects (eg a BinaryTree object) 假设有一个Tree对象,其中有一个root TreeNode对象,并且每个TreeNode都有leftNode和rightNode对象(例如BinaryTree对象)

If i call: 如果我打电话:

myTree = null;

what really happens with the related TreeNode objects inside the tree? 树内相关的TreeNode对象真正发生了什么? Will be garbage collected as well, or i have to set null all the related objects inside the tree object?? 也会收集垃圾,还是我必须将树对象内的所有相关对象设置为null?

Garbage collection in Java is performed on the basis of "reachability". Java中的垃圾收集是基于“可达性”进行的。 The JLS defines the term as follows: JLS对术语的定义如下:

"A reachable object is any object that can be accessed in any potential continuing computation from any live thread." “可达对象是可以从任何活动线程进行任何潜在的连续计算中访问的任何对象。”

So long as an object is reachable 1 , it is not eligible for garbage collection. 只要对象是可到达的1 ,就不符合垃圾回收的条件。

The JLS leaves it up to the Java implementation to figure out how to determine whether an object could be accessible. JLS将其留给Java实现来弄清楚如何确定对象是否可访问。 If the implementation cannot be sure, it is free to treat a theoretically unreachable object as reachable ... and not collect it. 如果无法确定实现,则可以自由地将理论上无法到达的对象视为可到达的对象...而不收集它。 (Indeed, the JLS allows an implementation to not collect anything, ever! No practical implementation would do that though 2 .) (实际上,JLS允许实现永远不收集任何东西!尽管2 ,也没有实际实现能做到这一点。)

In practice, (conservative) reachability is calculated by tracing; 在实践中,(保守)可达性是通过跟踪来计算的; looking at what can be reached by following references starting with the class (static) variables, and local variables on thread stacks. 通过遵循从类(静态)变量和线程堆栈上的局部变量开始的引用,可以了解可以达到的目标。


Here's what this means for your question: 这对您的问题意味着什么:

If i call: myTree = null; 如果我打电话: myTree = null; what really happens with the related TreeNode objects inside the tree? 树内相关的TreeNode对象真正发生了什么? Will be garbage collected as well, or i have to set null all the related objects inside the tree object?? 也会收集垃圾,还是我必须将树对象内的所有相关对象设置为null?

Let's assume that myTree contains the last remaining reachable reference to the tree root. 假设myTree包含对myTree的最后剩余可访问引用。

  1. Nothing happens immediately. 什么都不会立即发生
  2. If the internal nodes were previously only reachable via the root node, then they are now unreachable, and eligible for garbage collection. 如果以前只能通过根节点访问内部节点,那么现在它们是不可访问的,并且可以进行垃圾回收。 (In this case, assigning null to references to internal nodes is unnecessary.) (在这种情况下,不必为对内部节点的引用分配null 。)
  3. However, if the internal nodes were reachable via other paths, they are presumably still reachable, and therefore NOT eligible for garbage collection. 但是,如果内部节点可以通过其他路径访问,则它们可能仍然可以访问,因此不符合垃圾收集的条件。 (In this case, assigning null to references to internal nodes is a mistake. You are dismantling a data structure that something else might later try to use.) (在这种情况下,将null分配给对内部节点的引用是一个错误。您正在分解一个数据结构,以后可能会尝试使用该数据结构。)

If myTree does not contain the last remaining reachable reference to the tree root, then nulling the internal reference is a mistake for the same reason as in 3. above. 如果myTree 包含对myTree最后剩余可访问引用,则出于与上述3.相同的原因,使内部引用为myTree是错误的。


So when should you null things to help the garbage collector? 因此,什么时候应该 null可帮助垃圾收集器的内容?

The cases where you need to worry are when you can figure out that that the reference in some cell (local, instance or class variable, or array element) won't be used again, but the compiler and runtime can't! 您需要担心的情​​况是, 可以确定不再重用某些单元格(局部,实例或类变量或数组元素)中的引用,但是编译器和运行时不能使用! The cases fall into roughly three categories: 案件大致分为三类:

  1. Object references in class variables ... which (by definition) never go out of scope. 类变量中的对象引用...(根据定义)永远不会超出范围。
  2. Object references in local variables that are still in scope ... but won't be used. 仍在范围内的局部变量中的对象引用...但不会使用。 For example: 例如:

      public List<Pig> pigSquadron(boolean pigsMightFly) { List<Pig> airbornePigs = new ArrayList<Pig>(); while (...) { Pig piggy = new Pig(); ... if (pigsMightFly) { airbornePigs.add(piggy); } ... } return airbornePigs.size() > 0 ? airbornePigs : null; } 

    In the above, we know that if pigsMightFly is false, that the list object won't be used. 在上面, 我们知道如果pigsMightFly为false,则不会使用列表对象。 But no mainstream Java compiler could be expected to figure this out. 但是没有主流的Java编译器可以解决这个问题。

  3. Object references in instance variables or in array cells where the data structure invariants mean that they won't be used. 实例变量或数组单元中的对象引用(其中数据结构不变表示将不使用它们)。 @edalorzo's stack example is an example of this. @edalorzo的堆栈示例就是一个示例。

It should be noted that the compiler / runtime can sometimes figure out that an in-scope variable is effectively dead. 应该注意的是,编译器/运行时有时可以确定范围内变量实际上是无效的。 For example: 例如:

public void method(...) {
    Object o = ...
    Object p = ...
    while (...) {
        // Do things to 'o' and 'p'
    }
    // No further references to 'o'
    // Do lots more things to 'p'
}

Some Java compilers / runtimes may be able to detect that 'o' is not needed after the loop ends, and treat the variable as dead. 一些Java编译器/运行时可能能够在循环结束后检测到不需要'o',并将变量视为无效。


1 - In fact, what we are talking about here is strong reachability. 1-实际上,我们在这里谈论的是强大的可达性。 The GC reachability model is more complicated when you consider soft, weak and phantom references. 当考虑软引用,弱引用和幻像引用时,GC可达性模型更加复杂。 However, these are not relevant to the OP's use-case. 但是,这些与OP的用例无关。

2 - In Java 11 there is an experimental GC called the Epsilon GC that explicitly doesn't collect anything. 2-在Java 11中,有一个称为Epsilon GC的实验性GC ,它明确不收集任何内容。

myTree is just a reference variable that previously pointed to an object in the heap. myTree只是先前指向堆中对象的引用变量。 Now you are setting that to null. 现在,您将其设置为null。 If you don't have any other reference to that object, then that object will be eligible for garbage collection. 如果您没有对该对象的任何其他引用,则该对象将有资格进行垃圾回收。

To let the garbage collector remove the object myTree just make a call to gc() after you've set it to null 要让垃圾收集器删除对象myTree只需将其设置为null后调用gc()即可

myTree=null;
System.gc();

Note that the object is removed only when there is no other reference pointing to it. 请注意,仅当没有其他引用指向该对象时,该对象才被删除。

They will be garbage collected unless you have other references to them (probably manual). 除非您有其他引用(可能是手册),否则它们将被垃圾回收。 If you just have a reference to the tree, then yes, they will be garbage collected. 如果您仅引用树,则可以,它们将被垃圾收集。

You can't set an object to null , only a variable which might contain an pointer/reference to this object. 您不能将对象设置为null ,而只能将一个变量包含可能指向该对象的指针/引用。 The object itself is not affected by this. 对象本身不受此影响。 But if now no paths from any living thread (ie local variable of any running method) to your object exist, it will be garbage-collected, if and when the memory is needed. 但是,如果现在不存在从任何活动线程(即任何正在运行的方法的局部变量)到您的对象的路径,则在需要内存时以及在需要内存时都将对其进行垃圾回收。 This applies to any objects, also the ones which are referred to from your original tree object. 这适用于任何对象,也适用于从原始树对象引用的对象。

Note that for local variables you normally not have to set them to null if the method (or block) will finish soon anyway. 请注意,对于局部变量,如果方法(或块)将很快完成,通常不必将其设置为null

In Java, you do not need to explicitly set objects to null to allow them to be GC'd. 在Java中,您无需将对象显式设置为null即可对其进行GC处理。 Objects are eligible for GC when there are no references to it (ignoring the java.lang.ref.* classes). 如果没有对对象的引用(忽略java.lang.ref.*类),则对象可以使用GC。

An object gets collected when there are no more references to it. 没有更多引用可收集对象。

In your case, the nodes referred to directly by the object formally referenced by myTree (the root node) will be collected, and so on. 在您的情况下,将收集由myTree (根节点)正式引用的对象直接引用的节点,依此类推。

This of course is not the case if you have outstanding references to nodes outside of the tree. 如果您对树外部的节点有出色的引用,那么情况当然不是这样。 Those will get GC'd once those references go out of scope (along with anything only they refer to) 一旦这些引用超出范围(连同它们所引用的所有内容),它们将被GC

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

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