详解ThreadLocal为什么会内存溢出原理

Bunny ·
更新时间:2024-09-20
· 612 次阅读

目录

前言

ThreadLocal源码分析

ThreadLocal value内存溢出

总结

前言

关于ThreadLocal (线程本地存储),从字面意思上看主要是存储一些本地变量,使它们能在一个线程内共用,与其他的线程进行数据隔离,保证了数据在一个线程内的安全性,日常的开发中,ThreadLocal的使用场景还是比较常见的,包括登陆信息的token的存储、连接管理一个线程持有一个链接,该连接可以在不同的方法之间进行传递,一个线程内数据共享,通过key,value的形式存储数据。

ThreadLocal源码分析

ThreadLocal类有一个静态内部类,ThreadLocalMap可以看到内部有个Entry 数组k就是ThreadLocal的引用,Entry 继承了WeakReference 说明Entry 的k是个弱引用,从这看来如果是弱引用那么就不会存在内存溢出,GC运行的时候,这个对象就会被回收掉,value则是存储的对象,而ThreadLocalMap则是由threadLocals来创建的,可以看到这两个变量的默认都是NULL。

p>只有当线程第一次调用的时候才会创建它。

ThreadLocal value内存溢出

前面讲到ThreadLocal的key是threadlocals是弱引用不会存在内存溢出,那么容易存在内存溢出的一定是它的value,它与current thread 存在一个强引用的关系,导致value无法进行回收,如果线程的对象一直不去销毁这个强引用的对象,那么导致这个关系一直存在就会出现内存溢出,

/** * 内存溢出例子 */ public class ThreadLocalTest { static class Mytask{ //定义10m的Byte数组 private Byte[] bytes =new Byte[10 *1024 * 1024]; } private static ThreadLocal<Mytask> threadLocal = new ThreadLocal(); public static void main(String[] args) throws InterruptedException { // 5个核心线程、5个最大线程、队列长度100 ThreadPoolExecutor threadPoolExecutor =new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)); for (int i = 0; i < 10; i++) { //执行任务 executeTask(threadPoolExecutor); Thread.sleep(1000); } } private static void executeTask(ThreadPoolExecutor threadPoolExecutor){ threadPoolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("创建Mytask对象"); Mytask mytask =new Mytask(); threadLocal.set(mytask); } }); }

堆内存设置50m

通过上面代码,创建线程池对创建的任务,放入threadlocal里面,可以看到出现了堆内存的溢出,存放的任务一直在引用没有得到释放导致堆内存空间不足。

p>我们在set值到threadLocal后面加入finally,调用它的remove方法来清除它的内存那么就不会发生内存溢出。

来看看remove的代码,可以看到获取当前线程的threadLocals,然后调用remove方法获取到全部的Entry数组,判断不为空,key也是当前的key则调用clear方法将数组清除,这样数组空间得到了释放自然就不会出现内存溢出。

public void remove() { ThreadLocalMap m = getMap(Thread./currentThread/()); if (m != null) m.remove(this); } private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } 总结

ThreadLocal在使用的时候一定到进行remove,这也是一个比较常见的内存溢出的例子,希望大家引以为戒。

以上就是详解ThreadLocal为什么会内存溢出原理的详细内容,更多关于ThreadLocal内存溢出的资料请关注软件开发网其它相关文章!



threadlocal 内存溢出

需要 登录 后方可回复, 如果你还没有账号请 注册新账号