【问题标题】:Garbage collection example in java?java中的垃圾收集示例?
【发布时间】:2012-08-01 14:11:56
【问题描述】:
class Beta { }

class Alpha {
static Beta b1  ;
Beta b2;
}

public class Tester {

public static void main(String[] args) {

    Beta b1 = new Beta();
    Beta b2 = new Beta();
    Alpha a1 = new Alpha();
    Alpha a2 = new Alpha();

    a1.b1 = b1 ;
    a1.b2 = b1 ;
    a2.b2 = b2 ;

    a1 = null ;
    b1 = null;
    b2 = null;

    System.out.println(" Line 1    " + " a1   "  + a1.b1);
    System.out.println(" Line 2    " + " a1   "  + a1.b2);
    System.out.println(" Line 3    " + " a2   " + a2.b2);
    System.out.println(" Line 4    " + " a1   " + a2.b1);
    System.out.println(" Line 5    " + " b1   " + b1);
    System.out.println(" Line 6    " + " b1   " + b2);

  }

 }  

我不确定为什么上述程序中只有 a1 对象可用于垃圾回收。我希望垃圾收集器会收集 a1 、 b1 和 b2 。

如您所见 a1 、 b1 和 b2 被设为 NULL ,因此这使得对象可用于垃圾回收。如果对象为 NULL 或任何线程或引用变量都无法访问,则它应该由垃圾收集器收集。

有人可以通过很好的例子和更精确的方式帮助我理解上述程序的微妙之处吗?感谢您的帮助。

【问题讨论】:

  • 您不能在 Java 中“使对象为空”。不过,您可以取消对对象的 reference。无论如何,除非您使用弱引用等,否则您无法真正“观察”Java 中的垃圾回收。
  • 你是怎么发现 b1 和 b2 没有被垃圾回收的?

标签: java garbage-collection


【解决方案1】:

因为由于下面的行,仍然存在对 b1 和 b2 引用所指向的对象的引用。

a1.b1 = b1 ;
a1.b2 = b1 ;
a2.b2 = b2 ;

假设如下:

  b1--->BetaObj1
    b2---BetaObj2
    a1---> AlphaObj1
    a2---> AlphaObj2

a1.b1 指向 b1 这意味着,有对 BetaObj1 的引用 a1.b2 指向 b1,这意味着,还有另一个对 BetaObj1 的引用

(此时有3个对BetaObj1的引用)

a2.b2 指向 b2,这意味着存在对 BetaOBj2 的引用

(此时有2个对BetaObj2的引用)

a1=null; 使 AlphaObj1 符合 GC 条件

b1=null; 使 BetaObj1 引用计数为 2,因此该对象不符合 GC 条件

b2=null; 使 BetaObj2 引用计数为 1,因此该对象不符合 GC 条件。

【讨论】:

  • 我喜欢你的回答,尽管它与本页底部的 Daniel Fischer 先生的回答有点矛盾。假设 b1----> BetaObj1, a1.b1----> BetaObj1 和 a1.b2---->BetaObj1
  • 。当 a1 = null 时,哪个参考连接将被削减到 BetaObj1 ,是 a1.b1 还是 a1.b2 还是 b1 。我只期待您给出的答案中的 b1 而不是 a1.b1 和 a1.b2 。当我执行 a1.b2 时抛出 NullPointerException ,和 Fischer 先生说的一样。
  • Fischer 先生正在谈论静态 b1 实例变量。我知道静态实例变量不需要实例来访问。但是他为什么仅仅因为 b1 是静态的而说 a1.b1 将永远存在(可能是我在最后一点上错了,但我想不出比 Fischer 先生所说的静态更多)。你能帮我理解这个概念吗?我想我只是非常接近理解垃圾收集的概念。
  • 而且我也排除 a1.b1 抛出 NullPointerException。
【解决方案2】:
  • b2 不适用于 gc,因为它仍然有 a2.b2 的引用
  • b1 不适用于 gc,因为 Alpha.b1 持有对它的引用(Alpha.b1 是静态的,不要混淆,因为它是使用 a1.b1 设置的)

【讨论】:

    【解决方案3】:

    您应该在这里获得NullPointerException

    System.out.println(" Line 1    " + " a1   "  + a1.b1);
    System.out.println(" Line 2    " + " a1   "  + a1.b2);
    

    此时,a1 已设置为 null,因此无法访问其成员 b2,因为它不再引用对象。 (访问静态 b1 有效,因为这只需要类,而不是实例。)

    如您所见 a1 、 b1 和 b2 被设为 NULL 因此这使得对象可用于垃圾回收。

    不,您将这些对象的一些引用设置为null,而对这些对象的其他引用存在,就像b1b2 的情况一样,这些对象还不能被收集。

    【讨论】:

      【解决方案4】:

      这里有几个误解

      • GC 仅在需要时运行。比需要更频繁地执行 GC 将做它不需要的工作。
      • a1.b1 实际上是 Alpha.b1,因为实例并不重要,甚至可以是 null 使用 al.b1 很容易混淆。
      • a1.b2 应该抛出 NullPointerException,因为 a1 是 null
      • Alpha.b1 已设置但未在任何地方清除,因此它引用的对象不符合清除条件。可以清理其他对象,但无需显式调用 System.gc();,它不太可能需要在您预期的位置运行。
      • a1 已清除,但 a2 未清除,因此不会被清除(直到方法返回)

      【讨论】:

        【解决方案5】:

        垃圾回收示例

        public class GarbageCollection {
        
            public static void main(String s[]) throws Exception  {
                  Runtime rs =  Runtime.getRuntime();
                  System.out.println("Free memory in JVM before Garbage Collection = "+rs.freeMemory());
                  rs.gc();
                  System.out.println("Free memory in JVM after Garbage Collection = "+rs.freeMemory());
               }
        }
        

        程序输出:

        垃圾回收前 JVM 中的可用内存 = 62767488

        垃圾回收后 JVM 中的可用内存 = 62854120

        【讨论】:

          猜你喜欢
          • 2010-12-13
          • 2011-02-25
          • 1970-01-01
          • 2011-11-07
          • 1970-01-01
          • 2016-03-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多