weakreference和线程

sg2wtvxw  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(262)

我在试着理解 WeakReference 以及为什么下面的代码片段永远运行,即为什么 dummy 字符串永远不会被gc'd,尽管看起来删除了对它的所有引用?

import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

public class Test {
  public static void main(String[] args) {
    String dummy = new String("sdfsdfsdf");
    WeakReference<String> dummyRef = new WeakReference<>(dummy);

    Thread test = new Thread(
      () -> {
        while (true) {
          try {
            TimeUnit.SECONDS.sleep(1);
          } catch (InterruptedException e) {
          }

          String s = dummyRef.get();
          if (s == null) {
            System.out.println("String GC'd. Quitting.");
            break;
          }

          System.out.println(s);
          s = null;
        }
      }
    );
    test.start();

    try {
      dummy = null;
      TimeUnit.SECONDS.sleep(30);
    } catch (InterruptedException e) {
    }
  }
}

gc实际上是在这里运行,还是lambda持有对周围堆栈帧中对象的引用,尽管从未实际使用 dummy 直接变量?要使代码按预期工作,我需要做哪些更改?
这个用例是一个类的工厂方法,该类将生成一个线程,该线程以固定的间隔调用返回对象的方法。如果创建的对象被销毁(即允许对象被gc'd),我希望线程退出。

ryevplcw

ryevplcw1#

如果测试包含激活垃圾收集器的原因,那么测试应该可以工作。让我们添加一个只消耗内存的线程:

public class Test {
  public static void main(String[] args) {
    String dummy = new String("sdfsdfsdf");
    WeakReference<String> dummyRef = new WeakReference<>(dummy);

    // This thread creates arrays and chucks them.
    // Marked as a daemon to ensure it doesn't stop the program
    // from quitting.
    Thread memEater = new Thread(
      () -> {
          for( int i=1;;i++) {
              int[] arr = new int[6553500];
              arr[0] = i;
              try {
                  TimeUnit.SECONDS.sleep(1);
              } catch (InterruptedException e) {
              }
          }
      }
    );
    memEater.setDaemon(true);
    memEater.start();

    Thread test = new Thread(
      () -> {
        while (true) {
          try {
            TimeUnit.SECONDS.sleep(1);
          } catch (InterruptedException e) {
          }

          String s = dummyRef.get();
          if (s == null) {
            System.out.println("String GC'd. Quitting.");
            break;
          }

          System.out.println(s);
          s = null;
        }
      }
    );
    test.start();

    try {
      dummy = null;
      TimeUnit.SECONDS.sleep(30);
    } catch (InterruptedException e) {
    }
  }
}

我从中得到的结果是:

% java Test                                                                                                 
sdfsdfsdf
sdfsdfsdf
sdfsdfsdf
sdfsdfsdf
String GC'd. Quitting.

相关问题