【发布时间】:2017-05-08 15:20:06
【问题描述】:
我有一个线程本地对象,它使用非静态内部类的对象进行初始化,如下所示:
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,但内存使用量并没有下降。然后我进行了堆转储并分析了TObject 类创建的对象数量。它表明内存中所有 100,000 个对象都可用。
Screenshot of the heapdump, check out the object count
我将内部类设为静态意味着它不再强烈引用外部类对象并再次运行相同的代码。这里触发 GC 显着降低了内存使用量,内存中的对象数量只有 3000 个左右。
Screenshot of the heapdump with only 3000 objects
我不确定我是否理解:
在第一种情况下,outerObject 和 innerObject 相互持有强引用,但它们都没有从其他任何地方强引用。如果 threadlocalmap 只包含对 threadlocal 变量 (TObject) 的弱引用,并且我们没有在其他任何地方保存对外部对象 StressTestThreadLocal 的引用,为什么 threadlocal 对象不符合垃圾回收条件?为什么将内部类设为静态会自动解决这个问题?
【问题讨论】:
-
只是想知道:与stackoverflow.com/questions/30992479/threadlocal-memory-leak 有什么关系吗?
-
没有。那是关于线程局部变量是静态的。这是关于 threadlocal 是非静态内部类的对象的值。
-
如果您还有其他如此重要的问题,请告诉我。仍在寻找“赏金”的“受害者”;-)
-
哈哈!会做!虽然没有承诺。这样的问题很难提出:D
标签: java garbage-collection thread-local