当前位置: 首页 > news >正文

ThreadLocal内存泄漏分析

一、ThreadLocal内存泄漏分析

1.1 ThreadLocal实现原理

1.1.1、set(T value)方法

查看ThreadLocal源码的 set(T value)方法,可以发现数据是存在了ThreadLocalMap的静态内部类Entry里面

其中key为使用弱引用的ThreadLocal实例,value为set传入的值。核心源代码:

public void set(T value) {Thread t = Thread.currentThread();// ThreadLocalMap跟当前线程对象绑定,是线程对象中的一个成员属性ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);else// 第一次调用的时候,将当前线程和value往下传。createMap(t, value);
}
​
void createMap(Thread t, T firstValue) {// 当前线程内部的变量 ThreadLocal.ThreadLocalMap threadLocals 设置为新建出来的对象。t.threadLocals = new ThreadLocalMap(this, firstValue);
}
​
static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {Object value;
​Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}...
}

1.2 ThreadLocal 内存泄漏的原因

引用原理图如下,实心箭头表示强引用虚线箭头表示弱引用

1、图中所示,当前线程强引用了ThreadLocalMap,而ThreadLocal为ThreadLocalMap的弱引用Key。

2、结合1.2节知识背景,如果ThreadLocal没有被外部强引用,当系统触发GC时,会将ThreadLocal对象回收掉,会导致ThreadLocalMap的Key为null,但是value还是被当前线程强引用,只有当Thread线程退出后,value的强引用链才会断开。

3、如果线程不结束(比如使用了线程池),则引用链(Thread -> ThreadLocalMap -> Entry -> value)一直存在,永远不会被回收,从而造成内存泄漏。

1.2.1 代码演示内存泄漏
public class ThreadLocalTest {public static void main(String[] args) {//二、TheadLocal内存泄漏//2.1、局部代码块中创建ThreadLocal后不引用它。createThreadLocal();//2.2、让GC回收不再被强引用,只有弱引用的TheadLocal对象System.gc();//2.3、查看线程成员属性ThreadLocalMap中 存入的键值对(key为null,而value还在,出现内存泄漏问题)Thread thread = Thread.currentThread();}
​public static ThreadLocal<String> createThreadLocal(){ThreadLocal<String> threadLocal = new ThreadLocal<>();threadLocal.set("zs");return threadLocal;}
}
​

debug运行代码,查看当前线程的ThreadLocalMap中的数据,可以发现引用的Key已经被GC回收了,造成了内存泄漏

1.3 key为什么使用弱引用

即使没有手动删除key和value,ThreadLocal在没有被引用的时候也会被回收。即ThreadLocalMap的key为null,下一次ThreadLocalMap调用set()、get()、remove()方法的时候会清除没被回收的value。

1.3.1 代码演示清除没被回收的value
package com.adolesce.server.mutithread;
​
/*** @author Administrator* @version 1.0* @description: TODO* @date 2023/7/1 9:52*/
public class ThreadLocalTest {public static void main(String[] args) {//三、TheadLocal没被强引用后,触发System.gc(),将key回收,设为null//3.1、创建ThreadLocal对象ThreadLocal threadLocal = createThreadLocal();//3.2、模拟threadLocal没被引用:断点时手动将thread中ThreadLocalMap value为【zs】对应的key设为nullThread thread = Thread.currentThread();//3.3、测试get、set、remove方法将key为null的value清除threadLocal.get();//3.4、查看ThreadLocalMap中value是否为null了thread = Thread.currentThread();}
​public static ThreadLocal<String> createThreadLocal(){ThreadLocal<String> threadLocal = new ThreadLocal<>();threadLocal.set("zs");return threadLocal;}
}

调用get方法的时候,由于map中的value对应的key为null,通过当前ThreadLocal对象去获取是获取value是获取不到Entry,于是调用初始化value的方法,清除原来的value,如get源码:

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) { // 为null跳出判断@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue(); // 调用初始化value的方法,清除原来的value
}

二、ThreadLocal的正确使用方法

1、每次使用完ThreadLocal都调用它的remove()方法清除数据。

2、将ThreadLocal变量定义成 private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能

通过 ThreadLocal的弱引用访问到Entry的value值,进而清除掉 。

package com.adolesce.server.mutithread;
​
/*** @author Administrator* @version 1.0* @description: TODO* @date 2023/7/1 9:52*/
public class ThreadLocalTest {private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
​public static void main(String[] args) {//一、TheadLocal使用System.out.println("主线程开启,线程ID:" + Thread.currentThread().getId());//1.1、向ThreadLocalMap中存入键值对setData();//1.2、从ThreadLocal中获取数据getData();//1.3、清除(通常在拦截器的afterCompletion()方法中进行清除)removeData();}
​private static void setData() {threadLocal.set("zhangsan");System.out.println("在线程"+Thread.currentThread().getId()+"中向ThreadLocal中存入了姓名");}
​private static void getData() {String name = threadLocal.get();System.out.println("在线程"+Thread.currentThread().getId()+"中从ThreadLocal中取了姓名:" + name);}private static void removeData() {threadLocal.remove();}
}
​

三、总结

1、内存泄漏原因:我们使用ThreadLocal过程中,如果ThreadLocal对象强引用断掉后,只剩弱引用,ThreadLocal对象会被回收,此时ThreadLocal中的key会变为null,而value没有被回收,同时又由于ThreadLocalMap是Thread中的成员属性,与Thread对象的生命周期是一样长,如果当前线程一直未被销毁,又没有手动删除对应key,这样就会导致value内存泄漏。

2、使用弱引用可以多一层value回收的保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set()、get()、remove()的时候会被清除。

3、因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。

相关文章:

ThreadLocal内存泄漏分析

一、ThreadLocal内存泄漏分析 1.1 ThreadLocal实现原理 1.1.1、set(T value)方法 查看ThreadLocal源码的 set(T value)方法&#xff0c;可以发现数据是存在了ThreadLocalMap的静态内部类Entry里面 其中key为使用弱引用的ThreadLocal实例&#xff0c;value为set传入的值。核…...

第 30 章 XML

第 30 章 XML 1.IE 中的 XML 2.DOM2 中的 XML 3.跨浏览器处理 XML 随着互联网的发展&#xff0c;Web 应用程序的丰富&#xff0c;开发人员越来越希望能够使用客户端来操作 XML 技术。而 XML 技术一度成为存储和传输结构化数据的标准。所以&#xff0c;本章就详细探讨一下 Ja…...

VMware下的ubuntu显示文字太小的自适应显示调整

我的情况 我使用的是4K的32寸显示器&#xff0c;分辨率为 3840 x 2160&#xff0c;ubuntu版本为18.04&#xff0c;默认的情况下系统分辨率为 3466 x 1842。 ​ 此时&#xff0c;显示的文字很小&#xff0c;虽然可以看清&#xff0c;但也比较吃力&#xff0c;在VMware窗口…...

外贸网站怎么搭建对谷歌seo比较好?

外贸网站怎么搭建对谷歌seo比较好&#xff1f;搭建一个网站自然不复杂&#xff0c;但要想搭建一个符合谷歌seo规范的网站&#xff0c;那就要多注意了&#xff0c;你的网站做的再酷炫&#xff0c;再花里胡哨&#xff0c;但如果页面都是js代码&#xff0c;或者页面没有源代码内容…...

如何创建网络白名单

网络白名单&#xff08;Whitelist&#xff09;是指允许通过网络访问的特定设备、IP地址、应用程序或网站。与黑名单&#xff08;Blacklist&#xff09;相反&#xff0c;白名单机制默认阻止所有连接&#xff0c;只有在白名单中明确允许的访问才能通过。这种策略可以提高网络的安…...

前端动态创建svg不起效果?

document.createElement(path);诸如此类的创建一般都是不太行的 我在创建这个之后&#xff0c;虽然在网页上是有相应的结构&#xff0c;但是完全不显示 一般正确的创建方式为 document.createElementNS(http://www.w3.org/2000/svg,path);在使用document.createElementNS(“ht…...

三、Drf request对象

3.1django和drf中的request的区别 django中的request:用户请求对象和参数 drf中的request:将django中的request加了一层封装&#xff0c;又加了一些其它的参数 drf中的request._requestdjango中的request 3.2创建url路由和CBV class UserView(APIView):def get(self,requ…...

CMIS5.2_光模块切应用(Application Selection and Instantiation)

目录 重要概念 DP配置、应用声明、应用码的区别 Control Set Provision 和 Commission ApplyDPInit 和 ApplyImmediate 判断应用是否切换成功 以800G光模块的3个应用对应的DP配置举例 1*800G应用&#xff1a; 2*400G应用&#xff1a; 8*100G应用&#xff1a; 应用声明…...

网络安全 DVWA通关指南 DVWA Weak Session IDs(弱会话)

DVWA Weak Session IDs&#xff08;弱会话&#xff09; 文章目录 DVWA Weak Session IDs&#xff08;弱会话&#xff09;Low LevelMedium LevelHigh LevelImpossible Level 参考文献 WEB 安全靶场通关指南 相关阅读 Brute Force (爆破) Command Injection&#xff08;命令注入…...

828华为云征文|华为云 Flexus X 实例初体验

一直想有自己的一款的服务器&#xff0c;为了更好的进行家庭娱乐&#xff0c;甚至偶尔可以满足个人搭建开发环境的需求&#xff0c;直到接触到了华为云 Flexus X 云服务器。Flexus 云服务器 X 实例是面向中小企业和开发者打造的轻量级云服务器。提供快速应用部署和简易的管理能…...

欧科云链OKLink相约TOKEN2049:更全面、多元与安全

过去几日&#xff0c;OKLink 与全球 Web3 从业者与爱好者们相约狮城。在多场激动人心的活动上分享了我们的产品进展、有关于链上数据的专家观点以及打磨产品的经验。同时也听到了很多来自行业的宝贵声音。跟随我们的脚步&#xff0c;捕捉这充实一周的精彩瞬间&#xff1a; 1、…...

遥感影像-语义分割数据集:云数据集详细介绍及训练样本处理流程

原始数据集详情 简介&#xff1a;该云数据集包括150张RGB三通道的高分辨率图像&#xff0c;在全球不同区域的分辨率从0.5米到15米不等。这些图像采集自谷歌Earth的五种主要土地覆盖类型&#xff0c;即水、植被、湿地、城市、冰雪和贫瘠土地。 KeyValue卫星类型谷歌Earth覆盖区…...

【有啥问啥】SimAM(Similarity-Aware Activation Module)注意力机制详解

SimAM&#xff08;Similarity-Aware Activation Module&#xff09;注意力机制详解 引言 在计算机视觉领域&#xff0c;注意力机制通过引导模型关注图像中的关键区域&#xff0c;显著提升了模型处理和理解图像的能力。SimAM&#xff08;Similarity-Aware Activation Module&a…...

鸿蒙应用开发,如何保存登录信息

在鸿蒙应用开发中&#xff0c;保存登录信息是实现用户自动登录、个性化展示等功能的基础。以下是一些常用的保存登录信息的方法&#xff1a; 一、全局状态管理 对于简单的应用&#xff0c;可以在全局范围内定义一个类&#xff08;如UserManager&#xff09;&#xff0c;使用单…...

★ C++进阶篇 ★ map和set

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第四章----map和set ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博…...

Python知识点:如何使用Nvidia Jetson与Python进行边缘计算

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 如何使用Nvidia Jetson与Python进行边缘计算 Nvidia Jetson平台是专为边缘计算设…...

动态分配内存

目录 前言 一.malloc,free函数 1.malloc,free函数原型 2.使用方法 3.具体实例 4.注意事项 二.calloc函数 1.calloc函数原型 2.主要特点 3.使用案例 三.realloc函数 1.realloc函数原型 2.使用案例 3.注意事项 前言 动态内存是指在程序运行时&#xff0c;按需分配和…...

Unity Input System自动生成配置

参考视频 创建及配置新输入系统 New Input System&#xff5c;Unity2022.2 最新教程《勇士传说》入门到进阶&#xff5c;4K_哔哩哔哩_bilibili ProjectSettings设置 Unity编辑器菜单栏选择Edit->Project Settings->Player->Other Settings,将Api Compatibility Level…...

【Windows】在任务管理器中隐藏进程

在此前的一篇&#xff0c;我们已经介绍过了注入Dll 阻止任务管理器结束进程 -- Win 10/11。本篇利用 hook NtQuerySystemInformation 并进行断链的方法实现进程隐身&#xff0c;实测支持 taskmgr.exe 的任意多进程隐身。 任务管理器 代码&#xff1a; // dllmain.cpp : 定义 …...

【TypeScript学习】TypeScript基础学习总结二

主要记录ts中的类、接口与泛型 1.类 无论是在哪种语言中&#xff0c;类都是面向对象编程(OOP)的一个主要实现方式。能够实现代码更加灵活&#xff0c;更具有结构化。类作用都是提供一个模板&#xff0c;通过类可以创建多个具有相同结构的对象。 // 类的定义&#xff0c;与对象…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...