ThreadLocal的内存泄漏问题.

public abstract class AUtil {

    private static final ThreadLocal<String> localHashIds = ThreadLocal.withInitial(() -> "jing_li");

    public static String getMember() {
        return localHashIds.get();
    }
}

只使用了ThreadLocal.get()方法,并未使用ThreadLocal.remove()方法.想知道这段代码是否会引起内存泄漏问题?
我的理解:ThreadLocal强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,在这个过程中,Entry的key -> localHashIds,一直被强引用,导致Entry无法被GC回收,最终会发生内存泄漏.

阅读 4.7k
4 个回答

你这里不remove也不会造成“内存泄露”,某些文章有点过度解读了……

一般我们理解的内存泄露,是指那些“幽灵”对象,回收不了也找不到,更无法使用。比如从连接池获取连接但不释放,未释放的连接程序也没有再使用,但由于连接池还有引用无法被回收,这种属于连接泄露。

而你这个例子里ThreadLocal 不 remove 只是会导致这个对象还存在线程的 ThreadLocalMap 里,但这样也不能说内存泄露,其他线程再 get 的时候还是可以获取到该对象,还是可以继续使用

ThreadLocal 的“内存泄露”是指,ThreadRef -> ThreadLocal 这个引用断了(通常是局部变量的 ThreadLocal 才会这样),但 Thread 的 ThreadLocalMap 还是引用了 ThreadLocal 和 Val 对象,对于 ThreadLocal 和 Val 来说是泄露,和你是不是 Remove 没啥关系的

所以Entry是个弱引用,一定程度避免了这种问题

ThreadLocalMap内部Entry中key使用的是对ThreadLocal对象的弱引用,这为避免内存泄露是一个进步,因为如果是强引用,那么即使其他地方没有对ThreadLocal对象的引用,ThreadLocalMap中的ThreadLocal对象还是不会被回收,而如果是弱引用则这时候ThreadLocal引用是会被回收掉的,虽然对于的value还是不能被回收,这时候ThreadLocalMap里面就会存在key为null但是value不为null的entry项,虽然ThreadLocalMap提供了set,get,remove方法在一些时机下会对这些Entry项进行清理,但是这是不及时的,也不是每次都会执行的,所以一些情况下还是会发生内存泄露,所以在使用完毕后即使调用remove方法才是解决内存泄露的王道。

如果线程一直运行,当前线程的entry 确实不会被回收掉。不过这写法好像也没打算让它回收掉,所以这确实好像算不上内存泄漏。。。。。。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题