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

ThreadLoad如何防止内存溢出

优质博文:IT-BLOG-CN

从 ThreadLocalMap看 ThreadLocal使用不当的内存泄漏问题

【1】基础概念 : 首先我们先看看ThreadLocalMap的类图,我们知道 ThreadLocal只是一个工具类,他为用户提供getsetremove接口操作实际存放本地变量的threadLocals(调用线程的成员变量),也知道 threadLocals是一个ThreadLocalMap类型的变量,下面我们来看看ThreadLocalMap这个类。在此之前,我们回忆一下Java中的四种引用类型链接

【2】分析ThreadLocalMap内部实现: 我们知道ThreadLocalMap内部实际上是一个Entry数组private Entry[] table,我们先看看Entry的这个内部类

/*** 是继承自WeakReference的一个类,该类中实际存放的key是指向ThreadLocal的弱引用和与之对应的value值(该value值* 就是通过ThreadLocal的set方法传递过来的值)由于是弱引用,当get方法返回null的时候意味着回收引用*/
static class Entry extends WeakReference<ThreadLocal<?>> {/** value就是和ThreadLocal绑定的 */Object value;//k:ThreadLocal的引用,被传递给WeakReference的构造方法Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}
//WeakReference构造方法(public class WeakReference<T> extends Reference<T> )
public WeakReference(T referent) {super(referent); //referent:ThreadLocal的引用
}//Reference构造方法
Reference(T referent) {this(referent, null);//referent:ThreadLocal的引用
}Reference(T referent, ReferenceQueue<? super T> queue) {this.referent = referent;this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}

在这里插入图片描述

在上面的代码中,我们可以看出,当前ThreadLocal的引用k被传递给WeakReference的构造函数,所以ThreadLocalMap中的keyThreadLocal的弱引用。当一个线程调用ThreadLocalset方法设置变量的时候,当前线程的 ThreadLocalMap就会存放一个记录,这个记录的key值为ThreadLocal的弱引用,value就是通过set设置的值。如果当前线程一直存在且没有调用该ThreadLocalremove方法,如果这个时候别的地方还有对ThreadLocal的引用,那么当前线程中的ThreadLocalMap中会存在对ThreadLocal变量的引用和 value对象的引用,是不会释放的,就会造成内存泄漏。

考虑这个ThreadLocal变量没有其他强依赖,如果当前线程还存在,由于线程的ThreadLocalMap里面的key是弱引用,所以当前线程的ThreadLocalMap里面的ThreadLocal变量的弱引用在gc的时候就被回收,但是对应的value还是存在的这就可能造成内存泄漏(因为这个时候 ThreadLocalMap会存在keynull但是value不为nullentry )。

ThreadLocalMap中的Entrykey使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLocal依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的value不会被回收,这个时候Map中就可能存在keynull但是value不为null的项,这需要实际使用的时候使用完毕及时调用 remove方法避免内存泄漏。

如果使用线程池,由于线程可能并不是真正的关闭(比如newFixedThreadPool会保持线程一只存活)。因此,如果将一些大对象存放到ThreadLocalMap中,可能会造成内存泄漏。因为线程没有关闭,无法回收,但是这些对象不会再被使用了。如果希望及时回收对象,则可以使用Thread.remove()方法将变量移除。

ThreadLocal<Object> threadLocal = new ThreadLocal<>();
// 存储数据
threadLocal.set(someData);
// 使用完毕后清除
threadLocal.remove();

我们再看下ThreadLocal底层的源码:

public T get() { //获取当前线程Thread t = Thread.currentThread();  //获取当前线程的ThreadLocalMap变量ThreadLocalMap map = getMap(t);  if (map != null) {  ThreadLocalMap.Entry e = map.getEntry(this);  if (e != null) {  @SuppressWarnings("unchecked")  T result = (T)e.value;  return result;  }  }  return setInitialValue();  
}public void set(T value) {  Thread t = Thread.currentThread();  ThreadLocalMap map = getMap(t);  if (map != null)  map.set(this, value);  else  createMap(t, value);  
}public void remove() {  ThreadLocalMap m = getMap(Thread.currentThread());  if (m != null)  m.remove(this);  
}

remove()方法逻辑比较简单,首先获取当前线程的ThreadLocalMap对象,然后循环遍历key,将目标key以及对应的value都设置为null

private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);// 循环遍历目标key,然后将key和value都设置为nullfor (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();// 清理value值expungeStaleEntry(i);return;}}
}

使用try-with-resourcestry-finally块:如果你的ThreadLocal变量在需要清理的资源管理上下文中使用,可以使用try-with-resources(自动清理)或try-finally(手动清理)块来确保及时清理。

try (ThreadLocalResource resource = new ThreadLocalResource()) {// 使用 ThreadLocalResource
}
// 或者使用 try-finally
ThreadLocalResource resource = new ThreadLocalResource();
try {// 使用 ThreadLocalResource
} finally {resource.close(); // 在 close 方法中清理 ThreadLocal 变量
}

使用InheritableThreadLocal:如果需要在子线程中访问父线程的ThreadLocal变量,并且确保在子线程中正确清理,可以考虑使用InheritableThreadLocal。这个类允许子线程继承父线程的ThreadLocal变量,并在子线程完成后自动清理。

ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
threadLocal.set("Hello, Parent Thread");
Runnable childTask = () -> {String value = threadLocal.get(); // 子线程可以访问父线程的 ThreadLocal 变量// ...
};
Thread childThread = new Thread(childTask);
childThread.start();

相关文章:

ThreadLoad如何防止内存溢出

优质博文&#xff1a;IT-BLOG-CN 从 ThreadLocalMap看 ThreadLocal使用不当的内存泄漏问题 【1】基础概念 &#xff1a; 首先我们先看看ThreadLocalMap的类图&#xff0c;我们知道 ThreadLocal只是一个工具类&#xff0c;他为用户提供get、set、remove接口操作实际存放本地变…...

2024.8.19 学习记录 —— 作业

一、TCP机械臂测试 #include <myhead.h>#define SER_PORT 8888 // 与服务器保持一致 #define SER_IP "192.168.0.114" // 服务器ip地址int main(int argc, const char *argv[]) {// 创建文件描述符打开键盘文件int fd open("/dev/input/event1…...

Java 阿里云视频直播开发流程

首先来看一下直播效果 推流工具有很多种&#xff08;例如OBS、阿里云直播Demo推流、等等&#xff0c;我用的是芯象导播&#xff09;阿里播放器地址 一、直播基础服务概述 官方文档说明 二、直播域名配置需要两个域名&#xff08;推流域名、播流域名&#xff09; 官方文档说…...

SQLite 轻量级的嵌入式关系型数据库的替代软件

SQLite 是一个轻量级的嵌入式关系型数据库&#xff0c;由于其简单易用和跨平台的特性&#xff0c;被广泛应用于各种应用程序中。以下是一些可作为SQLite替代品的数据库软件或可视化管理工具&#xff1a; 1. **SQLiteStudio**&#xff1a;这是一个免费、开源的跨平台SQLite数据…...

Flutter-自适用高度PageView

需求 在 Flutter 中&#xff0c;PageView 是一个非常常用的组件&#xff0c;能够实现多个页面的滑动切换。然而&#xff0c;默认的 PageView 高度是固定的&#xff0c;这在展示不同高度的页面时&#xff0c;可能会导致不必要的空白或内容裁剪问题。为了使 PageView 能够根据每…...

群晖NAS本地搭建可远程交互的大型语言模型LLM聊天机器人

文章目录 前言1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 前言 本文主要分享如何在群晖NAS本地部署并运行一个基于大语言模型Llama 2的个人本地聊天机器人并结合内网穿透工具…...

TypeScript 构建工具之 webpack

在实际开发中&#xff0c;直接使用TypeScript 编译器的情况不多。 在项目中&#xff0c;需要使用构建工具对代码进行打包&#xff0c;不可能脱离项目使用TypeScript 编译器单独打包TypeScript 。 那如何将 webpack 和 TypeScript 进行集成&#xff1f; 参考文档&#xff1a; w…...

conda环境下在pycharm中调试scrapy项目

前提条件 已经创建好了conda环境已经安装好了scrapy框架项目初始化完成 编写一个爬虫脚本 import scrapyclass StackOverflowSpider(scrapy.Spider):name stackoverflowstart_urls [http://stackoverflow.com/questions?sortvotes]def parse(self, response):print("…...

contenteditable=“true“的标签限制字数的时候修改光标位置

contenteditable"true"的标签限制字数的时候修改光标位置 有时候input和textarea并不能完全满足ui需求&#xff0c;这个时候我们就用contenteditable"true"来将别的标签修改为可编辑状态&#xff0c;但当我们通过js修改了内容之后光标的位置就是一个问题&…...

51单片机-LED灯蜂鸣器数码管按键DS18B20温度传感器

LDE灯的相关程序 LED灯闪烁 LED流水灯 方法1 方法二&#xff1a; 因为P1口可以直接控制P1^0~P1^7的8个led灯&#xff0c;利用一个8位的二进制数字来进行控制即可。如果要点亮P1^0 只需要给P1口传递 1111 1110即可。 蜂鸣器的使用 什么是蜂鸣器&#xff1f; 蜂鸣器是一种一…...

笔记本一线品牌有哪些

笔记本电脑的一线品牌通常指的是在市场上具有较高市场份额、良好口碑、较强的技术实力和服务能力的品牌。根据目前的信息&#xff0c;笔记本电脑市场的一线品牌主要包括以下几个&#xff1a; 联想 (Lenovo)&#xff1a;联想在全球笔记本市场上的占有率较高&#xff0c;其产品线…...

mysql聚合函数和分组

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…...

ubuntu20.04+RealSenseD455

ubuntu20.04安装驱动双目相机RealSenseD455 安装环境安装RealSense SDK 2.0ROS包安装启动Realsense摄像头存在的 bugD455标定安装环境 系统:Ubuntu20.04 ROS:Noetic 视觉传感器:Intel RealSense D455 安装RealSense SDK 2.0 该安装有两种方式,一个是用命令安装,另一个是…...

WAF绕过技巧

WAF绕过技巧 WAF&#xff08;Web Application Firewall&#xff09;是一种安全系统&#xff0c;旨在监控和控制网络流量&#xff0c;以防止攻击&#xff0c;如SQL 注入、跨站脚本&#xff08;XSS&#xff09;和拒绝服务&#xff08;DoS&#xff09;。 WAF 可以通过多种方式绕过…...

HarmonyOS应用三之组件生命周期和参数传递

目录&#xff1a; 1、生命周期的执行顺序2、页面数据传递3、图片的读取4、数据的备份和恢复5、轮播图6、页面布局图 1、生命周期的执行顺序 /** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* yo…...

[Qt][Qt 网络][上]详细讲解

目录 0.概述1.UDP Socket1.核心API概览2.回显服务器3.回显客户端 0.概述 要使用Qt中有关网络编程的API&#xff0c;需要添加network模块 1.UDP Socket 1.核心API概览 主要的类有两个&#xff1a;QUdpSocket和QNetworkDatagramQUdpSocket表⽰⼀个UDP的socket⽂件 bind(const …...

读零信任网络:在不可信网络中构建安全系统21读后总结与感想兼导读

1. 基本信息 零信任网络&#xff1a;在不可信网络中构建安全系统 道格巴斯&#xff08;Doug Barth&#xff09; 著 人民邮电出版社,2019年8月出版 1.1. 读薄率 书籍总字数252千字&#xff0c;笔记总字数73194字。 读薄率73194252000≈29.5% 这个读薄率是最高的吧&#x…...

Java基础——注释

在开发中注释是必不可少的&#xff0c;帮助我们更好的标记阅读代码&#xff0c;下面介绍几种常用的注释方式。 一、注释种类 1. 单行注释 使用//一行代码来进行注释&#xff0c;只能注释一行内容 2. 多行注释 使用斜杠星号的方式 /*注释多行代码*/&#xff0c;注释多行代…...

Redis未授权访问漏洞利用合集

一、基本信息 靶机&#xff1a;IP:192.168.100.40 攻击机&#xff1a;IP:192.168.100.60 二、漏洞 & 过程 Redis 未授权访问漏洞利用无口令远程登录靶机 靶机 cd redis-4.0.8/src./redis-server ../redis.conf 攻击机 ./redis-cli -h 192.168.100.40 Redis 未授权访问…...

基于asp.net的在线考试系统、基于c#的在线考试管理系统

摘 要 伴随着社会以及科学技术的发展&#xff0c;互联网已经渗透在人们的身边&#xff0c;网络慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;管理系统这一名词已不陌生&#xff0c;越来越多的学校、公司等机构都会定制一款属于自己个…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...