性能文章>记一次内存泄露,但并未溢出的问题 #论程序员,你曾遇到关于性能的那些事#>

记一次内存泄露,但并未溢出的问题 #论程序员,你曾遇到关于性能的那些事#原创

3年前
632534

起因:服务器日常巡检发现内存占用较高,一直在报警线附近。(忘记截图~~)
排查过程:
1、看了一下当时的监控图,在业务请求量不大的情况下内存占用率长期较高,且fullgc后内存占用率没有明显下降,初步推断可能存在内存泄露。于是dump出堆转储文件。使用HeapAnalyzer工具进行分析。
image.png
发现StackData类型相关对象占用堆内存过高。

2、查看代码发现,该对象被代码耗时打印工具类引用。
image.png
同时使用 ThreadLocal 存储方法调用树(对象大小受调用深度以及调用次数影响)以及调用时间。

因ThreadLocal为map数据结构。value部分为强引用,生命周期一般与线程生命周期一致。而java web容器采用线程池方式,线程长期存活,工具类未调用ThreadLocal中remove()方法释放。导致内存泄露。

另外也是因为当前场景ThreadLocal本身受到web容器线程池大小和本身业务方法调用深度限制,虽然内存泄露,但并未溢出。

3、许多工程同样引用该工具类,为何内存使用情况未有明显异常?

通过内存分析工具查看ThreadLocal对象相当一部分大小在2.8M左右,输出对象打印内容
image.png
查看该方法对应代码:
image.png

List对象CityInfo 元素有600多个,所以此处有600多次循环,会不断增大ThreadLocal大小,导致内存泄露问题突出。

问题高速我们:threadlocal 使用完成必须remove。

本文正在参与「论程序员,你曾遇到关于性能的那些事丨 PerfMa技术征文」活动

点赞收藏
changfeng
请先登录,查看3条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步
4
3