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

发布于 2024-11-02 00:05:04 字数 215 浏览 1 评论 0原文

假设,有一个 Tree 对象,有一个根 TreeNode 对象,每个 TreeNode 都有 leftNode 和 rightNode 对象(例如 BinaryTree 对象)

如果我调用:

myTree = null;

树内相关的 TreeNode 对象到底会发生什么?也会被垃圾收集,或者我必须将树对象内的所有相关对象设置为空?

Lets assume, there is a Tree object, with a root TreeNode object, and each TreeNode has leftNode and rightNode objects (e.g a BinaryTree object)

If i call:

myTree = null;

what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

燕归巢 2024-11-09 00:05:04

Java中的垃圾收集是在“可达性”的基础上进行的。 JLS对该术语的定义如下:

“可到达的对象是可以在任何潜在的持续计算中从任何活动线程访问的任何对象。”

只要对象是可到达的1,它就没有资格垃圾收集。

JLS 将其留给 Java 实现来确定如何确定对象是否可以访问。如果实现无法确定,则可以自由地将理论上无法访问的对象视为可访问的......而不收集它。 (事实上​​,JLS 允许实现永远不收集任何内容!但没有实际的实现可以做到这一点2。)

在实践中,(保守的)可达性是通过跟踪计算的;查看以下以类(静态)变量和线程堆栈上的局部变量开头的引用可以到达的内容。


这对你的问题意味着什么:

如果我调用:myTree = null; 树中相关的 TreeNode 对象到底会发生什么?也会被垃圾收集,或者我必须将树对象内的所有相关对象设置为 null??

我们假设 myTree 包含对树根的最后剩余的可到达引用。

  1. 没有什么会立即发生。
  2. 如果内部节点以前只能通过根节点访问,那么它们现在无法访问,并且有资格进行垃圾收集。 (在这种情况下,没有必要将 null 分配给内部节点的引用。)
  3. 但是,如果可以通过其他路径访问内部节点,则它们可能仍然可访问,因此不符合垃圾收集资格。 (在这种情况下,将 null 分配给内部节点的引用是一个错误。您正在拆除一个数据结构,其他东西稍后可能会尝试使用。)

如果 myTree 包含对树根的最后剩余可到达的引用,那么清空内部引用是一个错误,原因与上面3.中相同。


那么什么时候应该null东西来帮助垃圾收集器呢?

您需要担心的情​​况是,您可以发现某些单元格中的引用(本地、实例或类变量或数组元素)不会再次使用,但编译器和运行时不能!这些情况大致分为三类:

  1. 类变量中的对象引用......(根据定义)永远不会超出范围。
  2. 局部变量中的对象引用仍在范围内...但不会被使用。例如:

     public List; pigSquadron(布尔pigsMightFly) {
       列表<猪> airbornePigs = new ArrayList();
       尽管 (...) {
         小猪小猪 = new Pig();
         ...
         如果(pigsMightFly){
           airbornePigs.add(小猪);
         }
         ...
       }
       返回airbornePigs.size() > 0 ?空降猪:空;
     }
    

    在上面,我们知道如果 pigsMightFly 为 false,则不会使用列表对象。但主流 Java 编译器无法解决这个问题。

  3. 实例变量或数组单元格中的对象引用,其中数据结构不变量意味着它们不会被使用。 @edalorzo 的堆栈示例就是一个例子。

应该注意的是,编译器/运行时有时会发现作用域内的变量实际上已经死亡。例如:

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'
}

某些Java编译器/运行时可能能够在循环结束后检测到不需要'o',并将该变量视为死变量。


1 - 事实上,我们在这里讨论的是可达性。当考虑软引用、弱引用和幻像引用时,GC 可达性模型会更加复杂。但是,这些与 OP 的用例无关。

2 - 在 Java 11 中,有一个实验性 GC,称为 Epsilon GC 明确不收集任何东西。

Garbage collection in Java is performed on the basis of "reachability". The JLS defines the term as follows:

"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 reachable1, it is not eligible for garbage collection.

The JLS leaves it up to the Java implementation to figure out how to determine whether an object could be accessible. 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 though2.)

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; what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??

Let's assume that myTree contains the last remaining reachable reference to the tree root.

  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.)
  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.)

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.


So when should you null things to help the garbage collector?

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. But no mainstream Java compiler could be expected to figure this out.

  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.

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.


1 - In fact, what we are talking about here is strong reachability. The GC reachability model is more complicated when you consider soft, weak and phantom references. However, these are not relevant to the OP's use-case.

2 - In Java 11 there is an experimental GC called the Epsilon GC that explicitly doesn't collect anything.

在风中等你 2024-11-09 00:05:04

它们将被垃圾收集,除非您有其他对它们的引用(可能是手动的)。如果您只有对树的引用,那么是的,它们将被垃圾收集。

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.

情痴 2024-11-09 00:05:04

您不能将对象设置为null,只能将可能包含该对象的指针/引用的变量设置为null。对象本身不受此影响。但是,如果现在不存在从任何活动线程(即任何正在运行的方法的局部变量)到您的对象的路径,那么当需要内存时,它将被垃圾收集。这适用于任何对象,也适用于从原始树对象引用的对象。

请注意,对于局部变量,如果方法(或块)很快就会完成,通常不必将它们设置为 null

You can't set an object to null, only a variable which might contain an pointer/reference to this object. The object itself is not affected by this. But if now no paths from any living thread (i.e. 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.

嗫嚅 2024-11-09 00:05:04

myTree 只是一个先前指向堆中对象的引用变量。现在您将其设置为空。如果您没有对该对象的任何其他引用,则该对象将有资格进行垃圾回收。

要让垃圾收集器删除对象 myTree,只需在将其设置为 null 后调用 gc()

myTree=null;
System.gc();

请注意,该对象仅当没有其他引用指向它时才被删除。

myTree is just a reference variable that previously pointed to an object in the heap. Now you are setting that to 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;
System.gc();

Note that the object is removed only when there is no other reference pointing to it.

把梦留给海 2024-11-09 00:05:04

在 Java 中,您不需要显式地将对象设置为 null 来允许它们被 GC。当没有对对象的引用时,对象有资格进行 GC(忽略 java.lang.ref.* 类)。

In Java, you do not need to explicitly set objects to null to allow them to be GC'd. Objects are eligible for GC when there are no references to it (ignoring the java.lang.ref.* classes).

甩你一脸翔 2024-11-09 00:05:04

当不再有对象的引用时,该对象就会被收集。

在您的情况下,将收集由 myTree (根节点)正式引用的对象直接引用的节点,依此类推。

如果您对树外部的节点有未完成的引用,那么情况当然并非如此。一旦这些引用超出范围(以及仅它们引用的任何内容),这些引用就会被 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.

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文