java thread 内存泄露_Java ThreadLocal 内存泄露问题分析及解决方法。
前言
在分析ThreadLocal导致的内存泄露前,需要普及了解一下内存泄露、强引用与弱引用以及GC回收机制,这样才能更好的分析为什么ThreadLocal会导致内存泄露呢?更重要的是知道该如何避免这样情况发生,增强系统的健壮性。
内存泄露
内存泄露为程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光,
广义并通俗的说,就是:不再会被使用的对象或者变量占用的内存不能被回收,就是内存泄露。
强引用与弱引用
强引用,使用最普遍的引用,一个对象具有强引用,不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。
如果想取消强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样可以使JVM在合适的时间就会回收该对象。
弱引用,JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。可以在缓存中使用弱引用。
GC回收机制-如何找到需要回收的对象
JVM如何找到需要回收的对象,方式有两种:引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收,
可达性分析法:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的,那么虚拟机就判断是可回收对象。引用计数法,可能会出现A 引用了 B,B 又引用了 A,这时候就算他们都不再使用了,但因为相互引用 计数器=1 永远无法被回收。
ThreadLocal的内存泄露分析
先从前言的了解了一些概念(已懂忽略),接下来我们开始正式的来理解ThreadLocal导致的内存泄露的解析。
实现原理
static class ThreadLocalMap {
static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
...
}
ThreadLocal的实现原理,每一个Thread维护一个ThreadLocalMap,key为使用弱引用的ThreadLocal实例,value为线程变量的副本。这些对象之间的引用关系如下,
实心箭头表示强引用,空心箭头表示弱引用
ThreadLocal 内存泄漏的原因
从上图中可以看出,hreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有thead线程退出以后,value的强引用链条才会断掉。
但如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
永远无法回收,造成内存泄漏。
那为什么使用弱引用而不是强引用??
我们看看Key使用的
key 使用强引用
当hreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。
key 使用弱引用
当ThreadLocalMap的key为弱引用回收ThreadLocal时,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set(),get(),remove()方法的时候会被清除value值。
ThreadLocalMap的remove()分析
在这里只分析remove()方式,其他的方法可以查看源码进行分析:
private void remove(ThreadLocal> key) {
//使用hash方式,计算当前ThreadLocal变量所在table数组位置
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
//再次循环判断是否在为ThreadLocal变量所在table数组位置
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
//调用WeakReference的clear方法清除对ThreadLocal的弱引用
e.clear();
//清理key为null的元素
expungeStaleEntry(i);
return;
}
}
}
再看看清理key为null的元素expungeStaleEntry(i):
java thread 内存泄露_Java ThreadLocal 内存泄露问题分析及解决方法。相关推荐
- Java遍历List和Map出现ConcurrentModificationException异常原因分析及解决方法
Java遍历 List 和 Map 出现 ConcurrentModificationException 异常原因分析及解决方法 一.单线程 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误 ...
- java导出excel 乱码_java导出excel时出现文件名乱码解决方法
java解决导出Excel时文件名乱码的方法示例:(推荐:java视频教程)String agent = request.getHeader("USER-AGENT").toLow ...
- Android使用Handler造成内存泄露的分析及解决方法
Android使用Handler造成内存泄露的分析及解决方法 参考文章: (1)Android使用Handler造成内存泄露的分析及解决方法 (2)https://www.cnblogs.com/xu ...
- Android 内存泄漏分析与解决方法
Android 内存泄漏分析与解决方法 参考文章: (1)Android 内存泄漏分析与解决方法 (2)https://www.cnblogs.com/start1225/p/6903419.html ...
- Java中 9 种常见的 CMS GC 问题分析与解决
目录 Java中 9 种常见的 CMS GC 问题分析与解决 1. GC 1.1 引言 1.2 概览 2. GC 基础 2.1 基础概念 2.2 JVM 内存划分 2.3 分配对象 2.4 收集对象 ...
- OutOfMemoryError:Java堆空间–分析和解决方法
java.lang.OutOfMemoryError:Java堆问题是在支持或开发复杂的Java EE应用程序时可能会遇到的最复杂的问题之一. 这篇简短的文章将为您提供此JVM HotSpot Out ...
- java应用 cpu占用过高问题分析及解决方法
主要介绍了java应用cpu占用过高问题分析及解决方法,具有一定参考价值,需要的朋友可以参考下. 使用jstack分析java程序cpu占用率过高的问题 1,使用jps查找出java进程的pid,如3 ...
- Java 提示“找不到或无法加载主类” 解决方法
Java 提示"找不到或无法加载主类" 解决方法 参考文章: (1)Java 提示"找不到或无法加载主类" 解决方法 (2)https://www.cnblog ...
- Java并发--ConcurrentModificationException(并发修改异常)异常原因和解决方法
Java并发--ConcurrentModificationException(并发修改异常)异常原因和解决方法 参考文章: (1)Java并发--ConcurrentModificationExce ...
最新文章
- 听说你,对薪酬待遇不太满意。。。
- DeleteInsert引发的Mysql死锁
- 加拿大大数据:正在升温的大数据市场
- jsp页面的相关复习
- ubuntu下使用vi退出终端出现乱码的解决方案
- 软件安装——在Vmware中安装CentOS7(转载)
- 学习记录:由技术而产品,由产品而商务
- 安装“万能解码器”还原真实“解码”
- 微服务测试:如何破解测试所面临的问题?测试的类型和范围你懂吗
- 蓝桥杯 方格问题 6x6的方格,沿着格子的边线剪开成两部分。 要求这两部分的形状完全相同
- 双色球网页历史数据爬取
- 【Windows Server 2019】DHCP服务器配置与管理——验证DHCP服务 备份与恢复DHCP数据 Ⅲ
- 蓝牙耳机连接笔记本后,音乐会断断续续,卡顿。
- 基于低代码为企事业单位打造督办事务管理一体化协同管控平台
- 用360查看本地dns
- 个人作业 项目alpha版本测试
- 处理器架构——多发射处理器技术
- Spark数据挖掘实例1:基于 Audioscrobbler 数据集音乐推荐
- The Top 50 ‘Pictures of the Day’ for 2011
- MySQL执行查询语句时出现停滞状态,出现Waiting for table metadata lock的问题
热门文章
- 10-27 插入学生总学分表 (10 分)
- C语言程序练习- L1-040 最佳情侣身高差 (10分)
- Java黑皮书课后题第5章:*5.47(商业:检测ISBN-13)ISBN-13是标识书籍的新标准。它使用13位数字d1d2d3~d12d13,d13是校验和。如果校验和为10,则替换为0。求所有数字
- 2012届华为校园招聘机试题
- 经典面试题:链表的相交与环问题
- C#中的深复制与浅复制
- Python学习-基础篇7 网络编程
- TCP/IP详解学习笔记(2)-数据链路层
- 开源通用爬虫框架YayCrawler-运行与调试
- java中的hashcode方法作用以及内存泄漏问题