一次完整的JVM堆外内存泄漏故障排查记录( 二 )


我联系上了WCS的值班人,将我们遇到的问题和他们描述了一下,他们回复我们,会在他们本地执行下写入操作的压测,看看能不能复现我们的问题 。
既然等待他们的反馈还需要时间,我们就准备先自己琢磨下原因 。
「我将怀疑的目光停留在了直接内存上,怀疑是由于接口调用量过大,客户端对nio使用不当,导致使用ByteBuffer申请过多的直接内存 。」

?
「画外音:最终的结果证明,这一个先入为主的思路导致排查过程走了弯路 。在问题的排查过程中,用合理的猜测来缩小排查范围是可以的,但最好先把每种可能性都列清楚,在发现自己深入某个可能性无果时,要及时回头仔细审视其他可能性 。」
?
沙箱环境复现为了能还原当时的故障场景,我在沙箱环境申请了一台压测机器,来确保和线上环境一致 。
「首先我们先模拟内存溢出的情况(大量调用接口):」
我们让脚本继续推送数据,调用我们的接口,我们持续观察内存占用 。
当开始调用后,内存便开始持续增长,并且看起来没有被限制住(没有因为限制触发Full GC) 。
一次完整的JVM堆外内存泄漏故障排查记录

文章插图
 
「接着我们来模拟下平时正常调用量的情况(正常量调用接口):」
我们将该接口平时正常的调用量(比较小,且每10分钟进行一次批量调用)切到该压测机器上,得到了下图这样的老生代内存和物理内存趋势:
一次完整的JVM堆外内存泄漏故障排查记录

文章插图
 

一次完整的JVM堆外内存泄漏故障排查记录

文章插图
 
「问题来了:为何内存会不断往上走吃满内存呢?」
当时猜测是由于JVM进程并没有对于直接内存大小进行限制(-XX:MaxDirectMemorySize),所以堆外内存不断上涨,并不会触发FullGC操作 。
「上图能够得出两个结论:」
  • 在内存泄露的接口调用量很大的时候,如果恰好堆内老生代等其他情况一直不满足FullGC条件,就一直不会FullGC,直接内存一路上涨 。
  • 而在平时低调用量的情况下, 内存泄漏的比较慢,FullGC总会到来,回收掉泄露的那部分,这也是平时没有出问题,正常运行了很久的原因 。
「由于上面提到,我们进程的启动参数中并没有限制直接内存,于是我们将-XX:MaxDirectMemorySize配置加上,再次在沙箱环境进行了测验 。」
结果发现,进程占用的物理内存依然会不断上涨,超出了我们设置的限制,“看上去”配置似乎没起作用 。
这让我很讶异,难道JVM对内存的限制出现了问题?
「到了这里,能够看出我排查过程中思路执着于直接内存的泄露,一去不复返了 。」
?
「画外音:我们应该相信JVM对内存的掌握,如果发现参数失效,多从自己身上找原因,看看是不是自己使用参数有误 。」
?
直接内存分析为了更进一步的调查清楚直接内存里有什么,我开始对直接内存下手 。由于直接内存并不能像堆内存一样,很容易的看出所有占用的对象,我们需要一些命令来对直接内存进行排查,我有用了几种办法,来查看直接内存里到底出现了什么问题 。
查看进程内存信息 pmappmap - report memory map of a process(查看进程的内存映像信息)
pmap命令用于报告进程的内存映射关系,是linux调试及运维一个很好的工具 。
pmap -x pid 如果需要排序  | sort -n -k3**执行后我得到了下面的输出,删减输出如下:
..00007fa2d4000000    8660    8660    8660 rw---   [ anon ]00007fa65f12a000    8664    8664    8664 rw---   [ anon ]00007fa610000000    9840    9832    9832 rw---   [ anon ]00007fa5f75ff000   10244   10244   10244 rw---   [ anon ]00007fa6005fe000   59400   10276   10276 rw---   [ anon ]00007fa3f8000000   10468   10468   10468 rw---   [ anon ]00007fa60c000000   10480   10480   10480 rw---   [ anon ]00007fa614000000   10724   10696   10696 rw---   [ anon ]00007fa6e1c59000   13048   11228       0 r-x-- libjvm.so00007fa604000000   12140   12016   12016 rw---   [ anon ]00007fa654000000   13316   13096   13096 rw---   [ anon ]00007fa618000000   16888   16748   16748 rw---   [ anon ]00007fa624000000   37504   18756   18756 rw---   [ anon ]00007fa62c000000   53220   22368   22368 rw---   [ anon ]00007fa630000000   25128   23648   23648 rw---   [ anon ]00007fa63c000000   28044   24300   24300 rw---   [ anon ]00007fa61c000000   42376   27348   27348 rw---   [ anon ]00007fa628000000   29692   27388   27388 rw---   [ anon ]00007fa640000000   28016   28016   28016 rw---   [ anon ]00007fa620000000   28228   28216   28216 rw---   [ anon ]00007fa634000000   36096   30024   30024 rw---   [ anon ]00007fa638000000   65516   40128   40128 rw---   [ anon ]00007fa478000000   46280   46240   46240 rw---   [ anon ]0000000000f7e000   47980   47856   47856 rw---   [ anon ]00007fa67ccf0000   52288   51264   51264 rw---   [ anon ]00007fa6dc000000   65512   63264   63264 rw---   [ anon ]00007fa6cd000000   71296   68916   68916 rwx--   [ anon ]00000006c0000000 4359360 2735484 2735484 rw---   [ anon ]


推荐阅读