简体   繁体   English

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

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

I have a threadlocal object which is initialized with an object of a non static inner class, like this: 我有一个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();
      }
    }
  }
}

I ran this program, attached jconsole, triggerred GC multiple times but the memory usage did not go down. 我运行了这个程序,附加了jconsole,多次触发GC,但内存使用量没有下降。 I then took a heapdump and analysed the number of objects created of TObject class. 然后我拿了一个heapdump并分析了TObject类创建的对象数量。 It showed that all 100,000 objects were available in the memory. 它显示内存中有所有100,000个对象。

Screenshot of the heapdump, check out the object count heapdump的屏幕截图,查看对象计数

I made the inner class static meaning that it is no longer strongly referencing the outer class object and ran the same code again. 我使内部类静态意味着它不再强烈引用外部类对象并再次运行相同的代码。 Here triggering the GC brought down the memory usage significantly and the number of objects in the memory were only around 3000. 这里触发GC显着降低了内存使用量,内存中的对象数量仅为3000左右。

Screenshot of the heapdump with only 3000 objects 只有3000个对象的heapdump的屏幕截图

What I am not sure I understand is this: 我不确定我理解的是:

In first case, the outerObject and the innerObject are holding strong references to each other but none of them are strongly referenced from anywhere else. 在第一种情况下,outerObject和innerObject保持对彼此的强引用,但是没有一个强引用其他任何地方。 If threadlocalmap only contains a weak reference to the threadlocal variable ( TObject ) and we did not save the reference to the outer object StressTestThreadLocal anywhere else, why was the threadlocal object not eligible for garbage collection? 如果threadlocalmap只包含对threadlocal变量( TObject )的弱引用,并且我们没有在其他地方保存对外部对象StressTestThreadLocal的引用,为什么threadlocal对象不符合垃圾回收的条件? And why did making the inner class static automatically solve this problem? 为什么让内部类静态自动解决这个问题呢?

Thread local map has a strong reference to the actual value (which is TObject in this case). 线程局部映射具有对实际值的强引用(在这种情况下为TObject)。 Only the key of the map (ThreadLocal) is a weak reference. 只有地图的关键字(ThreadLocal)才是弱引用。 The reason behind making the key a weak reference is to expunge the entry from the map when the key is no longer referenced. 将密钥作为弱引用的原因是在不再引用密钥时从地图中删除条目。 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/ThreadLocal.java?av=f#298 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; 
        }
    }

When the inner class is non-static, the object has a strong ref to StressTestThreadLocal which in turn has a strong ref to tObjectThreadLocal (which is the key in thread local map). 当内部类是非静态的时,该对象具有对StressTestThreadLocal的强引用,而StressTestThreadLocal又具有对tObjectThreadLocal(这是线程本地映射中的键)的强引用。 So the entry never gets garbage collected. 因此,条目永远不会被垃圾收集。

TLM -> TLM.Entry.Value (TObject) -> StressTestThreadLocal -> TLM.Entry.Key (ThreadLocal) TLM - > TLM.Entry.Value(TObject) - > StressTestThreadLocal - > TLM.Entry.Key(ThreadLocal)
where TLM = Thread local map 其中TLM =线程本地映射

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM