打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

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

threadlocal源码分析

/**

* 内存溢出例子

*/

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);

}

});

}

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

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

threadlocal value内存溢出

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

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

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

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;

}

}

}

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

总结

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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
一文搞懂 ThreadLocal 原理
Java面试必问:ThreadLocal终极篇 淦!
快速掌握并发编程---深入学习ThreadLocal
如何扩展和优化线程池?
图灵学院:java高并发之Executor
ThreadLocal&MDC内存泄漏问题
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服