JAVA问题定位大杂汇之java 虚拟机内存占用超出 -Xmx设置
最近一个同事遇到一个诡异的现象,jvm只分配了8G内存,可是通过top查看,该java进程占用了30G物理内存(该机最大内存32G)。该现象导致监控系统报警频繁并出现宕机。同事让我看下这个问题,我一看打消了他的疑惑。这个是一个非堆溢出问题,java进程占用了很多非堆内存,没有释放. NIO是引起该类问题的凶手,Groovy也会导致类似问题出现。非堆内存溢出,用jvm提供工具,是没有办法定位的。
最近一个同事遇到一个诡异的现象,jvm只分配了8G内存,可是通过top查看,该java进程占用了30G物理内存(该机最大内存32G)。该现象导致监控系统报警频繁并出现宕机。
同事让我看下这个问题,我一看打消了他的疑惑。这个是一个非堆溢出问题,java进程占用了很多非堆内存,没有释放. NIO是引起该类问题的凶手,Groovy也会导致类似问题出现。非堆内存溢出,用jvm提供工具,是没有办法定位的。Linux提宫了查看进程内存映射的命令pmap(Pmap 提供了进程的内存映射,pmap命令用于显示一个或多个进程的内存状态。其报告进程的地址空间和内存状态信息。)
pmap 分析结果如下:
请注意65404这一行,种种迹象表明,这个再加上它上面那一行(在这里是132)就是增加的那个64M)。64M左右的内存块有大概400个,
占用内存25G左右。注意了为什么内存块大小都是64M左右?为什么这么规整?这个64M就是一个关键突破口,以64M为关键字百度和
Google,果然找到了类似的问题。
问题的根源就是glibc的malloc在这里捣鬼。想知道Linux下glibc的内存管理机制,请自行查找相关文档。简而言之,glibc分配内存的时候,大内存从从中央分配区分配,小内存从线程创建时,预先分配的缓存区分配。glibc为了分配内存的性能的问题,使用了很多叫做arena的memory pool,缺省配置在64bit下面是每一个arena为64M,一个进程可以最多有 cores * 8个arena。假设你的机器是4核的,那么最多可以有4 * 8 = 32个arena,也就是使用32 * 64 = 2048M内存。 当然你也可以通过设置环境变量来改变arena的数量.例如export MALLOC_ARENA_MAX=1。
解决办法就是:export MALLOC_ARENA_MAX=1
更多推荐
所有评论(0)