记一次内存泄露,但并未溢出的问题 #论程序员,你曾遇到关于性能的那些事#原创
3年前
691834
起因:服务器日常巡检发现内存占用较高,一直在报警线附近。(忘记截图~~)
排查过程:
1、看了一下当时的监控图,在业务请求量不大的情况下内存占用率长期较高,且fullgc后内存占用率没有明显下降,初步推断可能存在内存泄露。于是dump出堆转储文件。使用HeapAnalyzer工具进行分析。
发现StackData类型相关对象占用堆内存过高。
2、查看代码发现,该对象被代码耗时打印工具类引用。
同时使用 ThreadLocal 存储方法调用树(对象大小受调用深度以及调用次数影响)以及调用时间。
因ThreadLocal为map数据结构。value部分为强引用,生命周期一般与线程生命周期一致。而java web容器采用线程池方式,线程长期存活,工具类未调用ThreadLocal中remove()方法释放。导致内存泄露。
另外也是因为当前场景ThreadLocal本身受到web容器线程池大小和本身业务方法调用深度限制,虽然内存泄露,但并未溢出。
3、许多工程同样引用该工具类,为何内存使用情况未有明显异常?
通过内存分析工具查看ThreadLocal对象相当一部分大小在2.8M左右,输出对象打印内容
查看该方法对应代码:
List对象CityInfo 元素有600多个,所以此处有600多次循环,会不断增大ThreadLocal大小,导致内存泄露问题突出。
问题高速我们:threadlocal 使用完成必须remove。
本文正在参与「论程序员,你曾遇到关于性能的那些事丨 PerfMa技术征文」活动
点赞收藏
分类: