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

标签 java garbage-collection

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

如果我打电话:

myTree = null;

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

最佳答案

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

"A reachable object is any object that can be accessed in any potential continuing computation from any live thread."

只要一个对象是可访问的1,它就没有资格进行垃圾回收。

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

在实践中,(保守的)可达性是通过追踪来计算的;查看从类(静态)变量和线程堆栈上的局部变量开始的引用可以达到什么。


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

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??

让我们假设 myTree 包含对树根的最后剩余的可访问引用。

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

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


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

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

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

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

    在上面,我们知道如果 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 - 事实上,我们在这里谈论的是strong可达性。当您考虑软引用、弱引用和幻像引用时,GC 可达性模型会更加复杂。但是,这些与 OP 的用例无关。

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

关于java - java中的垃圾收集器-将对象设置为null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5690309/

相关文章:

java - 一些消息在 log4j 多线程应用程序中被多次记录

java - 在 Mac 上运行 Java 批处理文件

apache-spark - Spark : how to estimate size of Eden? 中的垃圾收集调整

java - 如何阅读GC详细信息

java - java中集合的弱引用

java - JAXB 内容未实例化

java - 无法读取 JSON : Cannot construct instance of `java.util.LinkedHashMap`

java - Hibernate SELECT DISTINCT 行为

java - 关于垃圾收集器行为的查询

c# - 此代码会导致托管堆损坏吗?