簡體   English   中英

如果線程本地映射包含對threadlocal對象的弱引用,那么為什么它不是垃圾回收?

[英]If thread local map contains a weak reference to the threadlocal object, then why is it not garbage collected?

我有一個threadlocal對象,它使用非靜態內部類的對象初始化,如下所示:

public class StressTestThreadLocal {

  private final ThreadLocal<TObject> tObjectThreadLocal = ThreadLocal.withInitial(
      () -> new TObject(1000));

  private static ExecutorService executorService = Executors.newFixedThreadPool(4);

  private void startThread() {
    executorService.submit(tObjectThreadLocal::get);
  }

  public class TObject {
    List<Integer> test;

    TObject(int n) {
      test = new ArrayList<>();
      for (int i = 0; i < n; i++) {
        test.add(i);
      }
      System.out.println("Done making TObject " + UUID.randomUUID());
    }
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100000; i++) {
      StressTestThreadLocal testThreadLocal = new StressTestThreadLocal();
      testThreadLocal.startThread();
    }
    while (true) {
      try {
        Thread.sleep(10000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

我運行了這個程序,附加了jconsole,多次觸發GC,但內存使用量沒有下降。 然后我拿了一個heapdump並分析了TObject類創建的對象數量。 它顯示內存中有所有100,000個對象。

heapdump的屏幕截圖,查看對象計數

我使內部類靜態意味着它不再強烈引用外部類對象並再次運行相同的代碼。 這里觸發GC顯着降低了內存使用量,內存中的對象數量僅為3000左右。

只有3000個對象的heapdump的屏幕截圖

我不確定我理解的是:

在第一種情況下,outerObject和innerObject保持對彼此的強引用,但是沒有一個強引用其他任何地方。 如果threadlocalmap只包含對threadlocal變量( TObject )的弱引用,並且我們沒有在其他地方保存對外部對象StressTestThreadLocal的引用,為什么threadlocal對象不符合垃圾回收的條件? 為什么讓內部類靜態自動解決這個問題呢?

線程局部映射具有對實際值的強引用(在這種情況下為TObject)。 只有地圖的關鍵字(ThreadLocal)才是弱引用。 將密鑰作為弱引用的原因是在不再引用密鑰時從地圖中刪除條目。 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/ThreadLocal.java?av=f#298

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v; 
        }
    }

當內部類是非靜態的時,該對象具有對StressTestThreadLocal的強引用,而StressTestThreadLocal又具有對tObjectThreadLocal(這是線程本地映射中的鍵)的強引用。 因此,條目永遠不會被垃圾收集。

TLM - > TLM.Entry.Value(TObject) - > StressTestThreadLocal - > TLM.Entry.Key(ThreadLocal)
其中TLM =線程本地映射

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM