【转载】深入分析 ThreadLocal 内存泄漏问题
前言
ThreadLocal
的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。但是如果滥用 ThreadLocal
,就可能会导致内存泄漏。下面,我们将围绕三个方面来分析 ThreadLocal
内存泄漏的问题
ThreadLocal
实现原理ThreadLocal
为什么会内存泄漏ThreadLocal
最佳实践
ThreadLocal 实现原理
ThreadLocal
ThreadLocal
的实现是这样的:每个Thread
维护一个 ThreadLocalMap
映射表,这个映射表的 key
是 ThreadLocal
实例本身,value
是真正需要存储的 Object
。
也就是说 ThreadLocal
本身并不存储值,它只是作为一个 key
来让线程从 ThreadLocalMap
获取 value
。值得注意的是图中的虚线,表示 ThreadLocalMap
是使用 ThreadLocal
的弱引用作为 Key
的,弱引用的对象在 GC 时会被回收。
ThreadLocal
为什么会内存泄漏
ThreadLocalMap
使用ThreadLocal
的弱引用作为key
,如果一个ThreadLocal
没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal
势必会被回收,这样一来,ThreadLocalMap
中就会出现key
为null
的Entry
,就没有办法访问这些key
为null
的Entry
的value
,如果当前线程再迟迟不结束的话,这些key
为null
的Entry
的value
就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
永远无法回收,造成内存泄漏。
其实,ThreadLocalMap
的设计中已经考虑到这种情况,也加上了一些防护措施:在ThreadLocal
的get()
,set()
,remove()
的时候都会清除线程ThreadLocalMap
里所有key
为null
的value
。
但是这些被动的预防措施并不能保证不会内存泄漏:
- 使用
static
的ThreadLocal
,延长了ThreadLocal
的生命周期,可能导致的内存泄漏(参考ThreadLocal 内存泄露的实例分析)。 - 分配使用了
ThreadLocal
又不再调用get()
,set()
,remove()
方法,那么就会导致内存泄漏。
为什么使用弱引用
从表面上看内存泄漏的根源在于使用了弱引用。网上的文章大多着重分析ThreadLocal
使用了弱引用会导致内存泄漏,但是另一个问题也同样值得思考:为什么使用弱引用而不是强引用?
我们先来看看官方文档的说法:
To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.
为了应对非常大和长时间的用途,哈希表使用弱引用的 key。
下面我们分两种情况讨论:
- key 使用强引用:引用的
ThreadLocal
的对象被回收了,但是ThreadLocalMap
还持有ThreadLocal
的强引用,如果没有手动删除,ThreadLocal
不会被回收,导致Entry
内存泄漏。 - key 使用弱引用:引用的
ThreadLocal
的对象被回收了,由于ThreadLocalMap
持有ThreadLocal
的弱引用,即使没有手动删除,ThreadLocal
也会被回收。value
在下一次ThreadLocalMap
调用set
,get
,remove
的时候会被清除。
比较两种情况,我们可以发现:由于ThreadLocalMap
的生命周期跟Thread
一样长,如果都没有手动删除对应key
,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal
不会内存泄漏,对应的value
在下一次ThreadLocalMap
调用set
,get
,remove
的时候会被清除。
因此,ThreadLocal
内存泄漏的根源是:由于ThreadLocalMap
的生命周期跟Thread
一样长,如果没有手动删除对应key
就会导致内存泄漏,而不是因为弱引用。
ThreadLocal 最佳实践
综合上面的分析,我们可以理解ThreadLocal
内存泄漏的前因后果,那么怎么避免内存泄漏呢?
- 每次使用完
ThreadLocal
,都调用它的remove()
方法,清除数据。
在使用线程池的情况下,没有及时清理ThreadLocal
,不仅是内存泄漏的问题,更严重的是可能导致业务逻辑出现问题。所以,使用ThreadLocal
就跟加锁完要解锁一样,用完就清理。
原文:http://blog.xiaohansong.com/2016/08/06/ThreadLocal-memory-leak/
转载于:https://www.cnblogs.com/darknebula/p/8573782.html
【转载】深入分析 ThreadLocal 内存泄漏问题相关推荐
- 深入分析 ThreadLocal 内存泄漏问题
转载自 http://www.importnew.com/22039.html ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件 ...
- 【java】ThreadLocal 内存泄漏 代码演示 实例演示
1.概述 转载:ThreadLocal 内存泄漏 代码演示 实例演示 首先看文章:ThreadLocal内存泄露原因分析 相关文章: [高并发]ThreadLocal.InheritableThrea ...
- 聊一聊ThreadLocal内存泄漏的问题
回答任何一个问题的时候应该要遵循:明确题意-->深入浅出-->举例说明-->总结,这四个步骤很重要,可以让你沉着冷静,思路清晰,避免尴尬. 01 - 明确题意 明确题意的意思就是先 ...
- ThreadLocal内存泄漏原理解析
1.什么是内存泄漏问题? 内存泄漏 表示就是我们申请了内存,但是该内存一直无法释放: 内存泄漏会导致内存溢出问题: 申请内存时,发现申请内存不足,就会报错 : 2.在介绍ThreadLocal内存泄漏 ...
- Java并发编程笔记之ThreadLocal内存泄漏探究
使用 ThreadLocal 不当可能会导致内存泄露,是什么原因导致的内存泄漏呢? 我们首先看一个例子,代码如下: /*** Created by cong on 2018/7/14.*/ publi ...
- ThreadLocal内存泄漏问题
ThreadLocal可以存取各线程专属的变量副本,底层是通过ThreadLocalMap实现,存的K-V K:WeakReference弱引用 V:变量副本 一旦某线程长期存活,但ThreadLoc ...
- ThreadLocal 内存泄漏问题
本文说说ThreadLocal由于使用不当造成的内存泄漏问题 Thead和ThreadLocal的内存状况如下图,不了解的同学参考: 图解ThreadLocal核心原理 如果线程太多,每个线程的val ...
- 关于ThreadLocal内存泄漏的问题
什么是ThreadLocal? ThreadLoal 变量,线程实例变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本.这里有几点需要注意: 因为每个 Thre ...
- 【转载】gdi+ 内存泄漏
[转载]http://issf.blog.163.com/blog/static/1941290822009111894413472/ 最近用GDI+实现了几个自定义控件,但是发现存在内存泄露问题 B ...
最新文章
- 2016百度实习编程题:括号序列
- 数据库中插入英文数字正常,插入中文错误解决方案
- AIProCon在线大会笔记之Google李双峰:TensorFlow的最新进展
- POJ 1696 Space Ant(极角排序)【计算几何】
- Swap Letters CodeForces - 1215C(贪心)
- 基于 gRPC 和 .NET Core 的服务器流
- [转]kafka介绍
- Java面试知识点:Object类、Math类、BigDecimal类、自动装箱、拆箱
- python画画加粗_Matplotlib'粗体'字体 - python
- python开发环境的搭建和设置
- 饥荒显示服务器建立时遇到问题,饥荒显示创建服务器遇到问题重试 | 手游网游页游攻略大全...
- 在Ubuntu下看各种格式的电影──包括RMVB
- 错误:java 找不到符号
- 一对一网络课堂教室应用教程实例
- React中文文档之Forms
- java 抓取视频流 海康_海康SDK如何实现视频流转发
- Ubuntu下安装Python
- 新旧电脑数据如何迁移?电脑数据导入到另一台电脑
- 1108 String复读机 – PAT乙级真题
- 提交一个骗子喵喵源码站
热门文章
- python gmm em算法 2维数据_AI大语音(六)——混合高斯模型(GMM)(深度解析)...
- “玲珑杯”ACM比赛 Round #24: C. この戦いが終わったら(BFS+bitset优化暴力)
- bzoj 2281: [Sdoi2011]黑白棋 bzoj 4550: 小奇的博弈(Nimk博弈+DP)
- HDU 5701:中位数计数
- C++ STL vector容器的插入和删除
- [Python+sklearn] 拆分数据集为训练和测试子集 sklearn.model_selection.train_test_split()
- hbase工作 架构原理
- windows下安装Redis数据库
- python爬虫案例——csdn数据采集
- jQuery Mobile中单选按钮radio的data-*选项