什么是 ThreadLocal?内存泄露产生的原因又是什么?

回答·18
最热
最新
  • 内存泄露是因为每个线程会维护一个 ThreadLocalMap,它的 key 就是 ThreadLocal,value 是要存储到副本的对象,因为 ThreadLocal 是弱类型的,容易被 GC 回收,就导致 map 的 key 为空,从而产生内存泄露
  • threadlocal 是用来给当前线程单独存放值 value 的,threadlocal 中维护了一个内部类 threadlocalmap,threadlocalmap 中有个 entry 数组用来存放 threadlocal,value。 内存泄露的原因就是它内部是个弱引用,threadlocal 是个弱引用,会被 gc 回收掉,这样的话 key 就会是 null,但是 value 是强引用,-threadlocalmap-entry-value。
  • ThreadLocal 是本地线程对象,在不进行 remove 操作时,内部存储对象在线程中会始终有效,这在一些线程重用场景中尤其明显,所以维护不好就会出现内存泄露。
  • ①ThreadLocal 是本地线程副本,主要通过线程独享来解决并发问题,也就是说是每个线程都创建一个副本,通过这个方式保证线程安全 ②内存泄露是因为内部结构中的 ThreadLocalMap 的 Entry 导致的,如果 Entry 的 value 回收不了就会导致内存泄露
  • 简单理解为一个 Map。key 是当前线程的一个弱引用,value 就是你放的值。泄漏点 弱引用。
  • ThreadLocal是本地线程副本,主要是通过线程独享来解决并发问题,也就是每个线程都创建一个副本,通过这个方式保证线程安全,是典型的空间换取时间的策略 内存泄露是因为内部结构中的ThreadLocalMap的Entry导致的,如果Entry的value回收不了就导致了内存泄露 而调用TreadLocal的remove方法可以避免内存泄露
  • threadLocal 顾名思义就是线程本地的变量,数据只能为当前线程进行访问,存放的是 key-value 的形式。在 ThreadLocal 中存在一个 ThreadLocalMap 用来存放信息,其中 key 存放的就是当前 treadlocal 对象,是一个虚引用,value 为对应的值,为强引用。当线程结束时忘释放 threadlocal 时,由于 key 为弱引用,在 gc 之后将会被回收,但是 value 为强引用并不会回收。当线程被回收了之后,本身的 threadlocalmap 对象也会被回收。threadlocal 为了防止这种情况,在 set 和 get 的时候都会回收 key 为 null 的对应的节点的内存空间。但是当线程为线程池创建,在使用了 threadlocal 之后并没有将其回收,且之后线程使用过程中并未调用 get,set 方法,线程也不会被销毁,就存在了内存泄露的情况。
  • threadlocal 是一个方法壳,线程私有的数据是存储在 thread 对象内的, 而 threadlocal 是提供一系列方法操作当前线程的这些私有数据。这些私有数据装载在 threadlocalmap 上,key 是被弱引用的对象,value 不是,所以 key 一旦被 gc 发现就会被回收,这样就导致对应 value 无法获取(因为无法用一个 null 的 threadlocal 对象作为 key 映射到),value 就成为了无用对象(无法拿来使用)且没有及时回收,这就导致内存泄漏。一般要在用完 value 后调用 remove 回收的。
  • threadlocal 其实是一个用来复制对象的,在解决多线程安全带时候,不是我们通常意义上的加锁的思想,而是把那个公共资源复制副本让线程调用。而副本的复制是会消耗内存的,如果线程使用完副本对象之后。没有对副本对象进行移出处理,当很多的副本对象被创建也没有移出。内存就会溢出,所有 threadlocal 提供了 remove 方法来移出副本对象。
  • 看源码你就会很清楚了,Threadlocal 有一个内部类叫 threadlocalMap,这个 map 是在线程类里用到的。比如你创建了一个线程池,里面线程用到了 threadlocal 对象并 put 进去了值,那么当你线程执行完以后,线程并没有被回收,所以当下一个任务被该线程执行的时候就会查询到上一次这个线程放入 map 对象和值,就导致了内存泄露。使用 threadlocal 的时候要注意用完之后要 remove 掉,这样可以避免内存泄露!