ThreadLocal内存泄漏问题

引子:

内存泄漏:是指本应该被GC回收的无用对象没有被回收,导致内存空间的浪费,当内存泄露严重时会导致内存溢出。Java内存泄露的根本原因是:长生命周期的对象持有短生命周期对象的引用,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被GC回收。

内存溢出:就是我们常说的OOM(OutOfMemoryError)异常,简单理解就是内存不够了,通常发生在程序申请的内存超出了JVM中可用内存的大小,就会抛出OOM异常。在JVM内存区域中,除了程序计数器外其他的内存区域都有可能抛出OOM异常。

ThreadLocal很好地解决了线程之间需要数据隔离的问题,同时也引入了另一个问题,在应用程序中通常会使用线程池来管理线程,那么线程的生命周期与应用程序的生命周期基本保持一致,如果线程的数量很多,随着程序的运行,时间的推移,ThreadLocal类型的变量会越来越多,将会占用非常大的内存空间,从而产生内存泄漏,如果这些对象一直不被释放的话,可能会导致内存溢出。

 

大家先看一下内存图:

 

从图中可以看出,ThreadLocal对象存在于堆中,有栈中的强引用指向它,也有ThreadLocalMap中的entry的弱引用键指向他。

“弱引⽤:只要垃圾回收机制⼀运⾏,不管JVM的内存空间是否充⾜,都会回收该对象占⽤的内存。”

而随着程序的运行,栈中ThreadLocal的强引用会消亡,只剩下弱引用连接着ThreadLocal独享,由于ThreadLocalMap.Entity中的key是弱引用,所以堆中的ThreadLocal对象会被回收(只要发生GC,弱引用对象就会被回收),但是ThreadLocalMap⽣命周期和Thread是⼀样的,它这时候如果不被回收,就会出现这种情况:ThreadLocalMap的key没了,value还在,这就会造成了内存泄漏问题(由弱引用引起的内存泄漏)。

而对于线程来说,线程的生命周期与应用程序的生命周期基本保持一致,所以一直会存在:Current Thread Refefence -> Thread -> ThreaLocalMap -> Entry -> value -> Object的强引用,这样value所强引用的Object对象迟迟得不到回收,就会导致内存泄漏。

如何解决弱引用导致的内存泄露问题?

ThreadLocalMap的设计中已经考虑到这种情况,所以ThreadLocal的get()、set()、remove()的时候都会清除线程ThreadLocalMap里所有key为null的value。

一旦将value设置为null之后,就斩断了引用与真实内存之间的强引用,就能够真正的释放空间,防止内存泄漏。

但是这只是一种被动的方式,如果这些方法都没有被调用怎么办?那你就每次使用完ThreadLocal变量之后,执行remove方法。

总结:ThreadLocalMap中的弱引用以及调用ThreadLocal各种方法后的清理只是增加了一层防护手段,还是有可能会导致内存泄露,真正想防止内存泄漏,需要编码的规范,使用完ThreadLocal后,及时调用remove()方法释放内存空间。

 

那为什么还要维持一个弱引用呢?

设置ThreadLocal对象的弱引用,这样做的目的是确保ThreadLocal对象在没有其他强引用时可以被垃圾回收。

key设计成弱引⽤同样是为了防⽌内存泄漏(这是另一个原因引起的内存泄漏)。假如key被设计成强引⽤,如果ThreadLocal Reference被销毁,此时它指向ThreadLoca的强引⽤就没有了,但是此时key还强引⽤指向ThreadLoca,就会导致ThreadLocal不能被回收,这时候就发⽣了内存泄漏的问题。

两个内存泄漏问题是不一样的

  • 这里是ThreadLocal变量无法被回收,导致内存泄漏;

  • 而弱引用导致的则是Value指向的object无法被回收,导致内存泄漏;

总结

首先,如果让key使用强引用指向ThreadLocal,则ThreadLocal对象无法被回收,导致内存泄漏;为了解决这个问题,让key使用弱引用指向Threadlocal,而这也会导致了Value无法被回收,造成内存泄漏,如何解决呢?我们在使用完ThreadLocal对象后,及时使用remove方法释放内存空间即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/84998.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FastDFS+Nginx - 本地搭建文件服务器同时实现在外远程访问「端口映射」

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

基于swing的零件销售系统java jsp客户信息维护mysql源代码

本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于swing的零件销售系统 系统有1权限:管…

mac垃圾清理软件有哪些

随着使用时间的增加,mac系统会产生一些垃圾文件,影响系统的性能和稳定性。为了保持mac系统的高效,用户需要定期使用mac垃圾清理软件来清理系统缓存、日志、语言包等无用文件。CleanMyMac是一款功能强大的mac垃圾清理软件,它可以帮…

mysql通过binlog日志恢复误删数据

1、先查看binlog功能是否开启 show variables like %log_bin%;log_bin为ON说明可以使用binlog恢复,如果为OFF说明没有开启binlog。 2、删除部分数据做测试 3、查找binlog文件位置 show variables like %datadir%;cd /var/lib/mysqlls -l删除数据时间是在文件154与…

Linux知识点 -- Linux多线程(二)

Linux知识点 – Linux多线程(二) 文章目录 Linux知识点 -- Linux多线程(二)一、线程互斥1.背景概念2.多线程访问同一个全局变量3.加锁保护4.问题5.锁的实现 二、线程安全1.可重入与线程安全2.常见情况3.可重入与线程安全的联系 三…

Azure CLI 进行磁盘加密

什么是磁盘加密 磁盘加密是指在Azure中对虚拟机的磁盘进行加密保护的一种机制。它使用Azure Key Vault来保护磁盘上的数据,以防止未经授权的访问和数据泄露。使用磁盘加密,可以保护磁盘上的数据以满足安全和合规性要求。 参考文档:https://l…

基于swing的超市管理系统java仓库库存进销存jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于swing的超市管理系统 系统有3权限:管…

RHCE——四、Web服务器(理论篇)

Web服务器 一、Web服务器1、www简介1.1 常见Web服务程序介绍:1.2 服务器主机1.3 主要数据1.4 浏览器 2、网址及HTTP简介2.1 URL2.2 http请求方法:2.3 HTTP协议请求的工作流程: 3、www服务器的类型静态网站动态网站 二、快速安装Apache1、安装2、准备工作…

kafka--kafka的基本概念-topic和partition

一、kafka的基本概念-topic和partition 1、topic (主题 ) topic是逻辑概念 以Topic机制来对消息进行分类的,同一类消息属于同一个Topic,你可以将每个topic看成是一个消息队列。 生产者(producer)将消息发…

Android动态添加和删除控件/布局

一、引言 最近在研究RecyclerView二级列表的使用方法,需要实现的效果如下。 然后查了一些博客,觉得实现方式太过复杂,而且这种方式也不是特别受推荐,所以请教了别人,得到了一种感觉还不错的实现方式。实现的思路为&…

MySQL分页查询-性能优化

MySQL分页查询优化 一、背景二、原因三、解决四、原理探究 https://blog.csdn.net/hollis_chuang/article/details/130570281 一、背景 业务背景:给C端10万级别的用户,同时发送活动消息,活动消息分为6类。数据背景:mysql表有百万…

SpringBoot自动配置原理

Spring Boot 的自动配置可以根据添加的jar依赖,自动配置 Spring Boot 应用程序。例如,我们想要使用Redis,直接在POM文件中增加spring-boot-starter-data-redis依赖,然后我们配置下连接信息就可以使用了。 那么Spring Boot 是如何…

机器学习笔记之优化算法(十五)Baillon Haddad Theorem简单认识

机器学习笔记之优化算法——Baillon Haddad Theorem简单认识 引言 Baillon Haddad Theorem \text{Baillon Haddad Theorem} Baillon Haddad Theorem简单认识证明过程证明:条件 1 ⇒ 1 \Rightarrow 1⇒ 条件 2 2 2证明:条件 3 ⇒ 3 \Rightarrow 3⇒条件 1…

一个计算机专业的学生数据结构这门课学到什么程度才能算学的还不错?

数据结构之所以重要是因为它处于算法中的基础地位,与解决实际问题关系密切;而之所以不重要是因为课本上能学到的所有实现都已经有人造过轮子了,甚至已经作为很多语言的标准API存在了。 换句话来说,在以后的编码生涯中&#xff0c…

ceph集群的扩容缩容

文章目录 集群扩容添加osd使用ceph-deploy工具手动添加 添加节点新节点前期准备新节点安装ceph,出现版本冲突 ceph-deploy增加节点 集群缩容删除osd删除节点 添加monitor节点删除monitor节点使用ceph-deploy卸载集群 实验所用虚拟机均为Centos 7.6系统,8…

Leetcode74. 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非递减顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。 class…

【从零开始的rust web开发之路 二】axum中间件和共享状态使用

系列文章目录 第一章 axum学习使用 第二章 axum中间件使用 文章目录 系列文章目录前言一、中间件是什么二、中间件使用常用中间件使用中间件使用TraceLayer中间件实现请求日志打印自定义中间件 共享状态 前言 上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件…

防火墙+路由模式部署

一、防火墙 防火墙最主要功能是提供访问控制能力 防火墙默认管理口为ge0/0(部分型号有专门的MGT口),管理地址为https://192.168.1.250,默认管理口只开启了https和ping。登录防火墙串口,波特率为9600,默认…

【校招VIP】测试专业课之TCP/IP模型

考点介绍: 大厂测试校招面试里经常会出现TCP/IP模型的考察,TCP/IP协议是网络基础知识,但是在校招面试中很多同学在基础回答中不到位,或者倒在引申问题里,就丢分了。 『测试专业课之TCP/IP模型』相关题目及解析内容可点…

uniapp-滑块验证组件wo-slider

wo-slider是一款支持高度自定义的滑块验证组件,采用uniapp-vue2编写 采用touchstart、touchmove、touchend事件实现的滑块组件,支持H5、微信小程序(其他小程序未试过,可自行尝试) 可到插件市场下载尝试: https://ext.…