深入分析 ThreadLocal 内存泄漏问题

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。但是如果滥用 ThreadLocal,就可能会导致内存泄漏。下面,我们将围绕三个方面来分析 ThreadLocal 内存泄漏的问题

  • ThreadLocal 实现原理
  • ThreadLocal为什么会内存泄漏
  • ThreadLocal 最佳实践

ThreadLocal 实现原理

ThreadLocal
ThreadLocal的实现是这样的:每个Thread 维护一个 ThreadLocalMap 映射表,这个映射表的 keyThreadLocal 实例本身,value 是真正需要存储的 Object

也就是说 ThreadLocal 本身并不存储值,它只是作为一个 key 来让线程从 ThreadLocalMap 获取 value。值得注意的是图中的虚线,表示 ThreadLocalMap 是使用 ThreadLocal 的弱引用作为 Key 的,弱引用的对象在 GC 时会被回收。

ThreadLocal为什么会内存泄漏

ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现keynullEntry,就没有办法访问这些keynullEntryvalue,如果当前线程再迟迟不结束的话,这些keynullEntryvalue就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。

其实,ThreadLocalMap的设计中已经考虑到这种情况,也加上了一些防护措施:在ThreadLocalget(),set(),remove()的时候都会清除线程ThreadLocalMap里所有keynullvalue

但是这些被动的预防措施并不能保证不会内存泄漏:

  • 使用staticThreadLocal,延长了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,getremove的时候会被清除。

比较两种情况,我们可以发现:由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除

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

ThreadLocal 最佳实践

综合上面的分析,我们可以理解ThreadLocal内存泄漏的前因后果,那么怎么避免内存泄漏呢?

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

在使用线程池的情况下,没有及时清理ThreadLocal,不仅是内存泄漏的问题,更严重的是可能导致业务逻辑出现问题。所以,使用ThreadLocal就跟加锁完要解锁一样,用完就清理。

转载于:https://my.oschina.net/u/3664884/blog/1790985

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何将iPhone应用程序从应用程序库移动到主屏幕

Justin Duino贾斯汀杜伊诺(Justin Duino)So as to not clutter up your home screen, newly-downloaded apps from the App Store can be sent directly to the App Library. But what if you later want to open the app without digging through the library? Here’s how t…

luogu4389 付公主的背包

题目链接:洛谷 题目大意:现在有$n$个物品,每种物品体积为$v_i$,对任意$s\in [1,m]$,求背包恰好装$s$体积的方案数(完全背包问题)。 数据范围:$n,m\leq 10^5$ 这道题,看到…

Git与Github的连接与使用

2019独角兽企业重金招聘Python工程师标准>>> Git与Github的连接与使用 下面继续,使用git 将项目上传到GitHub上 首先要有GitHub账号,这就不用说了,没有的先注册,地址:https://github.com 没有仓库的话,先新…

ttl电路制作pong游戏_如何玩Mozilla Firefox的隐藏的独角兽Pong游戏

ttl电路制作pong游戏It seems like every browser has a hidden game these days. Chrome has a dinosaur game, Edge has surfing, and Firefox has . . . unicorn pong? Yep, you read that right—here’s how to play it. 这些天似乎每个浏览器都有一个隐藏的游戏。 Chrom…

nginx 注释配置及详解

前言 DMZ(Demilitarized Zone) 非军事区,生产环境 WEB 服务部署的区域,公司的架构为一台nginx 充当 load balance 服务,负载到两台 nginx 上面,反向代理至后台服务,但是nginx 用的全是默认配置加上 proxy_pass 和 upst…

为什么无法运行谷歌play_什么是Google Play积分,以及如何使用它们?

为什么无法运行谷歌playThe Google Play Store is home to thousands of apps, games, movies, e-books, and more. You might find yourself making a lot of purchases there, so why not get rewarded for it? That’s where Google Play Points come in. Google Play商店提…

2019年春季学期第三周作业

本周作业 本周请大家完成上周挑战作业的第一部分:给定一个整数数组(包含正负数),找到一个具有最大和的子数组,返回其最大的子数组的和。 例如:[1, -2, 3, 10, -4, 7, 2, -5]的最大子数组为[3, 10, -4, 7, 2] 1).实验代…

Linux实验二:linux 常用命令练习

ls命令 列出目录内容 echo命令 显示字符串 date命令 显示或设置系统的日期与时间 cal命令 显示日历 who命令 列出登录用户信息 chown命令 chgrp命令 改变文件所属的用户组 chmod命令 改变文件访问权限 find命令 在目录中搜索文件 转载于:https://www.cnblogs.com/nullno/p/87…

python数据类型之元组类型

#为何要有元组&#xff0c;存放多个值&#xff0c;元组不可变&#xff0c;更多的是用来做查询 t(1,[1&#xff0c;2,3],a,(1,2)) #ttuple((1,[1,2,3],a,(1,2))) # print(type(t)) <class tuple># #元组可以作为字典的key # d{(1,2):egon} # print(d,type(d),d[(1,2)])# …

短语密码_使用密码短语以提高安全性

短语密码Did you know that Windows supports using passwords of up to 127 characters? I don’t use passwords anymore, and I haven’t for years. I’ve switched to using password phrases instead. 您知道Windows支持使用最多127个字符的密码吗&#xff1f; 我不再使…

「单点登录与权限管理」系列概述

首先&#xff0c;感谢几位朋友在朋友圈转发我的文章&#xff0c;小声的告诉你们&#xff0c;是我主动让他们帮忙转发的&#xff1a;&#xff09;在朋友们的分享下&#xff0c;凌晨推送的一篇文章&#xff0c;阅读人数达到了280多&#xff0c;很满足&#xff0c;我会坚持写下去&…

Jupyter notebook: TypeError: __init__() got an unexpected keyword argument 'io_loop 问题

使用环境&#xff1a;Anaconda3&#xff08;Python3.6&#xff09; 创建一个新的notebook时&#xff0c;无法连接到kernel&#xff0c;terminal上显示错误为&#xff1a;TypeError: __init__() got an unexpected keyword argument io_loop 解决方法&#xff1a; conda install…

在Ubuntu Linux中获取上次访问的文件时间

Ubuntu Linux has a rich set of commands for manipulating and accessing files. The stat utility gives detailed access to file information, including last accessed and last modified file time. Ubuntu Linux具有一组丰富的用于操作和访问文件的命令。 stat实用程序…

MySQL新增从库

项目背景描述&#xff1a;在项目的开始只有一个MySQL实例在运行&#xff0c;后期因为安全性&#xff0c;压力&#xff0c;备份等原因需要在此实例的基础上面新增一个从库。分析&#xff1a;MySQL主从是基于binlog日志来实现的&#xff0c;那么需要主服务器开启binlog&#xff0…

第一个议题

① 在每个问题后面&#xff0c;请说明哪一章节的什么内容引起了你的提问&#xff0c;提供一些上下文 ② 列出一些事例或资料&#xff0c;支持你的提问 。 ③ 说说你提问题的原因&#xff0c;你说因为自己的假设和书中的不同而提问&#xff0c;还是不懂书中的术语&#xff0c;还…

在Windows Vista中使用符号链接

One of the long-awaited features in Windows Vista was the ability to use symbolic links, the way you can in linux. Sadly, they don’t work quite as well as they could, but it’s a big upgrade from prior versions, and has solved a number of problems for me …

shell学习笔记--自我总结

一、文件 touch file # 创建空白文件 rm -rf 目录名 # 不提示删除非空目录(-r:递归删除 -f强制) dos2unix # windows文本转linux文本 unix2dos # linux文本转windows文本 enca filename # 查看编码 安装 yu…

201671030107胡文艳实验三作业互评与改进报告

任务1&#xff1a;要给出所点评作业的链接地址&#xff0c;点评内容和阅读心得 读了你的这篇博客&#xff0c;一方面给我的印象就是排版整齐&#xff0c;内容充实&#xff0c;态度认真&#xff1b;另外一方面就是通过别人反省自己&#xff0c;看了你的博客&#xff0c;我觉得我…

进程handle获取线程_获取进程中的线程列表

进程handle获取线程The System.Diagnostics namespace contains functions that allow you to manage processes, threads, eventlogs and performance information. System.Diagnostics命名空间包含允许您管理进程&#xff0c;线程&#xff0c;事件日志和性能信息的函数。 The…

2018-3-28Linux系统管理(16)计算机网络基础

在这一章当中我们讲述计算机网络基础。一、计算机网络网络通信就像人与人之间的交流一样&#xff0c;说同一种语言&#xff0c;而后双方进行无障碍的通信交流&#xff0c;那么两台主机通信时&#xff0c;它们彼此交换数据的格式的前提为互相理解才可以&#xff0c;我们此前也有…