排除无限制的Java Resident Set Size(RSS)增长

我有一个独立的Java应用程序,它具有:

-Xmx1024m -Xms1024m -XX:MaxPermSize=256m -XX:PermSize=256m 

随着时间的推移它会占用越来越多的内存,开始交换(并减速)并最终死了很多次(不是OOM +转储,只是死了,没有/ var / log / messages)。

到目前为止我尝试了什么:

  1. 堆转储:活动对象从1G堆中取出200-300Mb – >确定堆
  2. 活动线程数相当不变(~60-70) – >确定线程堆栈
  3. JMX在某些时候停止回答(mb它答案但是超时较低)
  4. 关闭交换 – 它死得更快
  5. strace – 似乎一切都慢了下来,应用仍然没有死,并且不确定哪些东西看起来那里
  6. 检查顶部:VIRT增长到5.5Gb,RSS增长到3.7 Gb
  7. 检查vmstat(显然我们开始交换):

      --------------------------procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ Sun Jul 22 16:10:26 2012: rb swpd free buff cache si so bi bo in cs us sy id wa st Sun Jul 22 16:48:41 2012: 0 0 138652 2502504 40360 706592 1 0 169 21 1047 206 20 1 74 4 0 . . . Sun Jul 22 18:10:59 2012: 0 0 138648 24816 58600 1609212 0 0 124 669 913 24436 43 22 34 2 0 Sun Jul 22 19:10:22 2012: 33 1 138644 33304 4960 1107480 0 0 100 536 810 19536 44 22 23 10 0 Sun Jul 22 20:10:28 2012: 54 1 213916 26928 2864 578832 3 360 100 710 639 12702 43 16 30 11 0 Sun Jul 22 21:10:43 2012: 0 0 629256 26116 2992 467808 84 176 278 1320 1293 24243 50 19 29 3 0 Sun Jul 22 22:10:55 2012: 4 0 772168 29136 1240 165900 203 94 435 1188 1278 21851 48 16 33 2 0 Sun Jul 22 23:10:57 2012: 0 1 2429536 26280 1880 169816 6875 6471 7081 6878 2146 8447 18 37 1 45 0 
  8. sar还显示稳定的系统%增长=交换:

      15:40:02 CPU %user %nice %system %iowait %steal %idle 17:40:01 all 51.00 0.00 7.81 3.04 0.00 38.15 19:40:01 all 48.43 0.00 18.89 2.07 0.00 30.60 20:40:01 all 43.93 0.00 15.84 5.54 0.00 34.70 21:40:01 all 46.14 0.00 15.44 6.57 0.00 31.85 22:40:01 all 44.25 0.00 20.94 5.43 0.00 29.39 23:40:01 all 18.24 0.00 52.13 21.17 0.00 8.46 12:40:02 all 22.03 0.00 41.70 15.46 0.00 20.81 
  9. 检查pmap可以获得以下最大贡献者:

      000000005416c000 1505760K rwx-- [ anon ] 00000000b0000000 1310720K rwx-- [ anon ] 00002aaab9001000 2079748K rwx-- [ anon ] 
  10. 试图将我从pmap中获得的地址与strace抛弃的东西相关联,这给了我没有匹配

  11. 添加更多内存是不切实际的(稍后会出现问题)

  12. 切换JVM是不可能的(env不在我们的控制之下)

问题是: 我还可以尝试追踪问题的原因或尝试解决问题?

JVM中的某些东西正在使用“无限制”的非堆内存。 一些可能的候选人是:

  • 线程堆栈。
  • 由某些本机代码库分配的本机堆。
  • 内存映射文件。

当您进行线程堆栈转储时,第一种可能性将显示为大量(且不断增加)的线程数。 (检查一下……好吗?)

如果您的应用程序(或它使用的某些第三方库)不使用任何本机库,您可以(可能)消除第二个。

如果您的应用程序(或它使用的某些第三方库)不使用内存映射文件,您可以消除第三个。


我猜你没有看到OOME的原因是你的JVM被Linux OOM杀手杀死了。 JVM也可能在本机代码中拯救(例如由于malloc故障未得到正确处理),但我认为JVM崩溃转储更可能是结果……

问题出在附加的探查器库中 – 它记录了CPU调用/分配站点,因此需要内存来存储它。

所以,这里的人为因素 🙂

Java和glibc> = 2.10存在已知问题(包括Ubuntu> = 10.04,RHEL> = 6)。

治愈就是设定这个环境。 变量: export MALLOC_ARENA_MAX=4

有一篇关于设置MALLOC_ARENA_MAX的IBM文章https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

这篇博文说

已知驻留内存以类似于内存泄漏或内存碎片的方式蠕变。

在Google或SO上搜索MALLOC_ARENA_MAX以获取更多参考资料。

您可能还想调整其他malloc选项以优化分配内存的低碎片:

 # tune glibc memory allocation, optimize for low fragmentation # limit the number of arenas export MALLOC_ARENA_MAX=2 # disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt" export MALLOC_MMAP_THRESHOLD_=131072 export MALLOC_TRIM_THRESHOLD_=131072 export MALLOC_TOP_PAD_=131072 export MALLOC_MMAP_MAX_=65536