`
zys0523
  • 浏览: 31822 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ThreadLocal与内存回收

 
阅读更多

昨天看到tf因为threadlocal用完没有清理而导致OOM

实验一:

package main;

/**
 * User: zhangyangsheng
 * Date: 13-1-24
 * Time: 下午6:40
 */
public class ThreadLocalTest {
    ThreadLocal<Value> threadLocalPart = new ThreadLocal<Value>();
    static class Value{
        final int i;
        Value(int i){
            this.i = i;
        }
    }

    ThreadLocalTest setThreadVal(int i){
        threadLocalPart.set(new Value(i));
        return this;
    }

    int getThreadVal(){
        return threadLocalPart.get().i;
    }

    public static void main(String[] args) {
        int sum = 0;
        for(int i = -500000000;i<=500000000;i++){
            sum+= new ThreadLocalTest().setThreadVal(i).getThreadVal();
        }
        System.out.println(sum);
    }
}

 对应的GC

   

可以看到GC非常频繁,但并未出现OOM 
 实验二:调整get的算法,在get后把threadLocal清理掉

int getThreadVal(){
        int temp = threadLocalPart.get().i;
        threadLocalPart.remove();
        return temp;
    }

 

调整后GC非常平稳,相比之前少了很多

实验三

把get方法恢复为实验一的情况,把内部类的static修饰符去除

结果:

java.lang.OutOfMemoryError 
 - klass: 'java/lang/OutOfMemoryError'
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (exceptions.cpp:390), pid=8494, tid=4620660736
#  fatal error: ExceptionMark destructor expects no pending exceptions
#
# JRE version: 7.0_04-b21
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.0-b21 mixed mode bsd-amd64 compressed oops)
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/zhangyangsheng/opensource/NettyExample/hs_err_pid8494.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

Process finished with exit code 134

 由于OutOfMemory导致了虚拟机crash

 

原因分析:

1.由于ThreadLocalMap使用的Entry是继承自WeakReference,所以当该WeakReference不存在强引用时会被GC掉

static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }

   并且ThreadLocal在set的时候在key为null的时候会对value和entry进行清理

// If key not found, put new entry in stale slot
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);

 所以结果一比结果二进行GC频繁的原因是虚拟机要GC掉一部分WeakReference(Entry.key)来存放新申请的对象。

那么为什么实验三会导致OOM呢,由于非静态内部类会持有创建这个类的外部的引用,导致WeakReference存在一个强引用而不能被GC掉。

图示:

 GC后,由于key是WeakReference,且不存在强引用,所以被垃圾回收


向ThreadLocal中设置值时,发现key为null时会吧value清空



 最后该entry会被覆盖掉,内存成功回收

在非静态内部类的情况下应用是这样的


 

由于entry的value是非静态内部类,所以存在该内部类所对应的外部类的引用(ThreadLocalTest),而外部类又存在对ThreadLocal的强引用,导致key无法回收,key无法回收又带来value无法回收最终导致ThreadLocalMap被撑满。
 

 

  • 大小: 33.6 KB
  • 大小: 27.7 KB
  • 大小: 11.6 KB
  • 大小: 10.8 KB
  • 大小: 10.7 KB
  • 大小: 16.9 KB
分享到:
评论
2 楼 www19940501a 2016-04-04  
我想问如果在2的基础上,把内部类的static修饰符去除,还会出现oom吗?
1 楼 贾懂凯 2013-07-10  

相关推荐

    ThreadLocal 内存泄露的实例分析1

    然而,如果存在对 WebappClassLoader 的强引用,那么这个类加载器就无法被回收,进而导致了内存泄漏。 在描述的案例中,`LeakingServlet` 是一个使用了 `ThreadLocal` 的 Servlet。`ThreadLocal` 是 Java 中用于在...

    ThreadLocal中内存泄漏和数据丢失问题的问题浅析及解决方案.docx

    ThreadLocal 被 ThreadLocalMap 中的 entry 的 key 弱引用,如果出现 GC 的情况时,没有被其他对象引用,会被回收,但是 ThreadLocal 对应的 value 却不会回收,容易造成内存泄漏。这也间接导致了内存溢出以及数据...

    ThreadLocal内存泄露分析

    【标题】:“ThreadLocal内存泄露分析” 在Java编程中,ThreadLocal是一个强大的工具类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。然而,...

    ThreadLocal

    - 内存泄漏:如果线程长时间存活,或者ThreadLocal对象没有被正确清理,可能导致ThreadLocalMap中的引用无法被垃圾回收,从而造成内存泄漏。 - 不适用于跨线程通信:ThreadLocal只保证同一线程内的数据隔离,不同...

    Java中ThreadLocal的设计与使用

    ### ThreadLocal内存泄漏问题 由于ThreadLocal变量是存储在线程的ThreadLocalMap中,如果线程长时间运行并且不清理ThreadLocal,当ThreadLocal对象被垃圾收集时,其在ThreadLocalMap中的引用将变为"幽灵引用"(弱...

    java中ThreadLocal详解

    1. **弱引用**:由于`ThreadLocalMap`的键使用弱引用,因此当没有强引用指向某个`ThreadLocal`时,JVM会在下一次垃圾回收时回收该`ThreadLocal`对象。 2. **expungeStaleEntry方法**:当`ThreadLocal`对象被垃圾...

    ThreadLocal原理及内存泄漏原因

    让我们深入理解ThreadLocal的工作原理以及可能导致内存泄漏的原因。 首先,ThreadLocal是如何实现每个线程都有独立变量副本的呢?这主要得益于内部类`ThreadLocalMap`。当一个ThreadLocal对象被创建后,它并没有...

    threadLocal

    3. 内存管理:了解Java的内存模型和垃圾回收机制,才能理解ThreadLocal的内存泄漏风险和弱引用的作用。 4. HTTP相关:虽然题目中没有直接涉及,但HTTPClient是一个常见的网络通信工具,经常和ThreadLocal结合使用,...

    正确理解ThreadLocal.pdf

    当线程结束时,与之关联的所有`ThreadLocal`变量也将自动被垃圾回收器回收。然而,如果线程持续运行但不再使用某些`ThreadLocal`变量,应显式调用`remove()`方法释放这些变量,避免内存泄漏。 #### 五、ThreadLocal...

    2、导致JVM内存泄露的ThreadLocal详解

    `ThreadLocal`类内部维护了一个`ThreadLocalMap`结构,该结构存储了线程与线程局部变量之间的映射关系。每当一个新的线程创建并首次访问某个`ThreadLocal`实例时,都会在该线程的`ThreadLocalMap`中添加一个新的键值...

    ThreadLocal_ThreadLocal源码分析_

    Entry继承自WeakReference&lt;ThreadLocal&gt;,这意味着ThreadLocal对象如果不再被引用,可以被垃圾收集器回收,避免内存泄漏。然而,这种设计也存在一个问题:如果ThreadLocal没有被外部引用,但其对应的Entry还在Map中...

    ThreadLocal的用处

    但是,如果ThreadLocalMap中的值(通常是对象)仍然被其他强引用保持,那么即使ThreadLocal实例被回收,值仍然存在于ThreadLocalMap中,这可能导致内存泄漏。因此,务必在不再使用ThreadLocal变量时调用`remove()`。...

    ThreadLocal整理.docx

    ThreadLocal 整理 ThreadLocal 是 Java 中... ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本,解决 Hash 冲突的机制是通过斐波那契数来实现的,并且提供了扩容机制来避免内存泄漏的问题。

    ThreadLocal原理及在多层架构中的应用

    - **弱引用**:ThreadLocalMap的键使用的是弱引用,当ThreadLocal变量不再被引用时,垃圾收集器可以回收ThreadLocal对象,但其在ThreadLocalMap中的引用不会立即被移除,以防止导致内存泄漏。 - **线程生命周期**:...

    ThreadLocal简单Demo

    1. **创建与初始化**: 当我们创建一个`ThreadLocal`实例时,并不会立即分配内存空间。只有当第一次调用`set()`或`get()`方法时,才会为当前线程创建一个对应的存储空间。 2. **内部类ThreadLocalMap**: `...

    ThreadLocal相关

    2. 生命周期:ThreadLocal 变量的生命周期与线程的生命周期相同,当线程结束时,ThreadLocal 变量将被垃圾回收。 3. private static:ThreadLocal 实例通常是 private static 类型的,用于关联线程和线程上下文。 ...

    JDK的ThreadLocal理解(一)使用和测试

    当线程结束时,与该线程相关的ThreadLocalMap会随之销毁,但ThreadLocal实例不会自动被垃圾回收。因此,如果不再使用ThreadLocal,建议显式调用`remove()`方法,以避免内存泄漏。 ### 3. ThreadLocal的工作原理 ...

    ThreadLocal内存泄漏思维导图完整版

    内存泄漏就是JVM垃圾回收器对某个对象占据的内存在较长时间内一直没法回收,没法回收的原因并不是因为垃圾回收器有bug,而是由于对象没法判定为垃圾(但实际上该对象已经是不会被使用了)。这里说的“较长时间”是一...

    ThreadLocal,你真的了解吗?

    了解 ThreadLocal,首先需要掌握 Java 中的四种引用类型,因为它们与 ThreadLocal 的内存管理策略息息相关。 1. 强引用(Strong Reference): - 强引用是最常见的引用类型,只要对象被强引用指向,就不会被垃圾...

Global site tag (gtag.js) - Google Analytics