ThreadLocal是一种confinement,confinement和local及immutable都是线程安全的(如果JVM可信的话)。因为对每个线程和value之间存在hash表,而线程数量未知,从表象来看ThreadLocal会存在内存泄露,读了代码,发现实际上也可能会内存泄露。
事实上每个Thread实例都具备一个ThreadLocal的map,以ThreadLocal Instance为key,以绑定的Object为Value。而这个map不是普通的map,它是在ThreadLocal中定义的,它和普通map的最大区别就是它的Entry是针对ThreadLocal弱引用的,即当外部ThreadLocal引用为空时,map就可以把ThreadLocal交给GC回收,从而得到一个null的key。
这个threadlocal内部的map在Thread实例内部维护了ThreadLocal Instance和bind value之间的关系,这个map有threshold,当超过threshold时,map会首先检查内部的ThreadLocal(前文说过,map是弱引用可以释放)是否为null,如果存在null,那么释放引用给gc,这样保留了位置给新的线程。如果不存在slate threadlocal,那么double threshold。除此之外,还有两个机会释放掉已经废弃的threadlocal占用的内存,一是当hash算法得到的table index刚好是一个null key的threadlocal时,直接用新的threadlocal替换掉已经废弃的。另外每次在map中新建一个entry时(即没有和用过的或未清理的entry命中时),会调用cleanSomeSlots来遍历清理空间。此外,当Thread本身销毁时,这个map也一定被销毁了(map在Thread之内),这样内部所有绑定到该线程的ThreadLocal的Object Value因为没有引用继续保持,所以被销毁。
从上可以看出Java已经充分考虑了时间和空间的权衡,但是因为置为null的threadlocal对应的Object Value无法及时回收。map只有到达threshold时或添加entry时才做检查,不似gc是定时检查,不过我们可以手工轮询检查,显式调用map的remove方法,及时的清理废弃的threadlocal内存。需要说明的是,只要不往不用的threadlocal中放入大量数据,问题不大,毕竟还有回收的机制。
综上,废弃threadlocal占用的内存会在3中情况下清理:
1 thread结束,那么与之相关的threadlocal value会被清理
2 GC后,thread.threadlocals(map) threshold超过最大值时,会清理
3 GC后,thread.threadlocals(map) 添加新的Entry时,hash算法没有命中既有Entry时,会清理
那么何时会“内存泄露”?当Thread长时间不结束,存在大量废弃的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中)时。
分享到:
相关推荐
但这里,`ThreadLocal` 的设计使得其内部的引用(即使是最弱的引用)在类加载器试图卸载时依然存在,这就形成了一个内存泄漏点。 解决这个问题的关键在于,我们需要确保在不再需要 `ThreadLocal` 变量时,及时清除...
【标题】:“ThreadLocal内存泄露分析” 在Java编程中,ThreadLocal是一个强大的工具类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。然而,...
ThreadLocal 中内存泄漏和数据丢失问题的问题浅析及解决方案 ThreadLocal 是 Java 中的一种线程本地存储机制,它可以解决线程之间的数据传递问题。然而,在使用 ThreadLocal 时,可能会出现内存泄漏和数据丢失问题...
内存泄漏就是JVM垃圾回收器对某个对象占据的内存在较长时间内一直没法回收,没法回收的原因并不是因为垃圾回收器有bug,而是由于对象没法判定为垃圾(但实际上该对象已经是不会被使用了)。这里说的“较长时间”是一...
04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、...
让我们深入理解ThreadLocal的工作原理以及可能导致内存泄漏的原因。 首先,ThreadLocal是如何实现每个线程都有独立变量副本的呢?这主要得益于内部类`ThreadLocalMap`。当一个ThreadLocal对象被创建后,它并没有...
然而,如果不正确地使用ThreadLocal,可能会导致内存泄露,尤其是在Java EE容器如Tomcat中。本文将深入探讨这个问题,并提供解决方案。 在问题背景部分,我们看到一个示例,其中`LeakingServlet`类内部使用了一个...
### 导致JVM内存泄露的ThreadLocal详解 #### 一、为什么要有ThreadLocal 在多线程编程中,为了避免线程间的数据竞争和保证线程安全性,常常需要使用同步机制如`synchronized`来控制线程对共享资源的访问。然而,...
### 关于Java内存泄漏 #### 一、Java内存管理机制 Java的一大特色在于其自动化的内存管理机制,这主要依赖于垃圾收集器(Garbage Collection, GC)来自动完成对象的内存分配与回收。尽管这一特性极大地减轻了...
当线程结束时,与其关联的ThreadLocal变量不会自动清除,可能会导致内存泄漏。因此,推荐在不再使用ThreadLocal时显式调用`remove()`方法。 ```java threadLocal.remove(); ``` ### 示例:线程安全的计数器 假设...
- 内存泄漏:如果线程长时间存活,或者ThreadLocal对象没有被正确清理,可能导致ThreadLocalMap中的引用无法被垃圾回收,从而造成内存泄漏。 - 不适用于跨线程通信:ThreadLocal只保证同一线程内的数据隔离,不同...
### ThreadLocal内存泄漏问题 由于ThreadLocal变量是存储在线程的ThreadLocalMap中,如果线程长时间运行并且不清理ThreadLocal,当ThreadLocal对象被垃圾收集时,其在ThreadLocalMap中的引用将变为"幽灵引用"(弱...
需要注意的是,尽管使用了弱引用来避免内存泄漏,但仍需谨慎管理`ThreadLocal`实例的生命周期,确保及时释放不再使用的资源。此外,`ThreadLocalMap`通过开放地址法来解决哈希冲突,进一步提高了性能并减少了内存...
内存泄露:是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄露, 一次的内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存溢出 JMM 决定一个线程对共享变量的写入何时对另一个线程可见,...
Entry继承自WeakReference<ThreadLocal>,这意味着ThreadLocal对象如果不再被引用,可以被垃圾收集器回收,避免内存泄漏。然而,这种设计也存在一个问题:如果ThreadLocal没有被外部引用,但其对应的Entry还在Map中...
3. 内存管理:了解Java的内存模型和垃圾回收机制,才能理解ThreadLocal的内存泄漏风险和弱引用的作用。 4. HTTP相关:虽然题目中没有直接涉及,但HTTPClient是一个常见的网络通信工具,经常和ThreadLocal结合使用,...
- **内存泄漏风险**:如果不正确地使用ThreadLocal,如忘记清理ThreadLocal变量,可能导致内存泄漏。 - **线程隔离性**:ThreadLocal只在创建它的线程内有效,无法跨线程共享数据。 - **难以调试**:由于ThreadLocal...
ThreadLocal 整理 ThreadLocal 是 Java 中... ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本,解决 Hash 冲突的机制是通过斐波那契数来实现的,并且提供了扩容机制来避免内存泄漏的问题。
4. ThreadLocal:如果线程局部变量未被正确清理,可能会导致内存泄漏。 5. 注册监听器未取消:注册的监听器如果没有在适当的时候解除注册,会持续持有对对象的引用。 四、内存泄漏的检测方法 1. **手动代码审查**...