java 虚拟内存占用很多,Java 进程占用 VIRT 虚拟内存超高的问题

1.现象

最近发现线上机器java 8进程的VIRT虚拟内存使用达到了11G+:

fbf2b517ad57e8a78d69b67e651246b3.png2.不管用的-Xmx

首先第一想到的当然使用java的-Xmx去限制堆的使用。但是无论怎样设置,都没有什么效果。没办法,只好开始苦逼的研究。

3.什么是VIRT

现代操作系统里面分配虚拟地址空间操作不同于分配物理内存。在64位操作系统上,可用的最大虚拟地址空间有16EB,即大概180亿GB。那么在一台只有16G的物理内存的机器上,我也能要求获得4TB的地址空间以备将来使用。例如:

void *mem = mmap(0, 4ul * 1024ul * 1024ul * 1024ul * 1024ul,

PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS |MAP_NORESERVE,

-1, 0);

当使用mmap并设置MAP_NORESERVE标志时,并不会要求实际的物理内存和swap空间存在。所以上述代码可以在top中看到使用了4096g的VIRT虚拟内存,这当然是不可能的,它只是表示使用了4096GB的地址空间而已。

4.为什么会用这么多地址空间

那Java程序为什么会使用这么多的地址空间呢?使用“pmap -x”来查看一下:

00007ff638021000   65404       0       0 -----    [ anon ]

00007ff63c000000     132      36      36 rw---    [ anon ]

00007ff63c021000   65404       0       0 -----    [ anon ]

00007ff640000000     132      28      28 rw---    [ anon ]

00007ff640021000   65404       0       0 -----    [ anon ]

00007ff644000000     132       8       8 rw---    [ anon ]

00007ff644021000   65404       0       0 -----    [ anon ]

00007ff648000000     184     184     184 rw---    [ anon ]

00007ff64802e000   65352       0       0 -----    [ anon ]

00007ff64c000000     132     100     100 rw---    [ anon ]

00007ff64c021000   65404       0       0 -----    [ anon ]

00007ff650000000     132      56      56 rw---    [ anon ]

00007ff650021000   65404       0       0 -----    [ anon ]

00007ff654000000     132      16      16 rw---    [ anon ]

00007ff654021000   65404       0       0 -----    [ anon ]

发现有很多奇怪的64MB的内存映射,查资料发现这是glibc在版本2.10引入的arena新功能导致。CentOS 6/7的glibc大都是2.12/ 2.17了,所以都会有这个问题。这个功能对每个线程都分配一个分配一个本地arena来加速多线程的执行。

在glibc的arena.c中使用的mmap()调用就和之前的示例代码类似:

p2 = (char *)mmap(aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,

MAP_NORESERVE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)

之后,只有很小的一部分地址被映射到了物理内存中:

mprotect(p2, size, PROT_READ | PROT_WRITE)

因此在一个多线程程序中,会有相当多的64MB的arena被分配。这个可以用环境变量MALLOC_ARENA_MAX来控制。在64位系统中的默认值为128。

5. Java的特殊性

Java程序由于自己维护堆的使用,导致调用glibc去管理内存的次数较少。更糟的是Java 8开始使用metaspace原空间取代永久代,而元空间是存放在操作系统本地内存中,那线程一多,每个线程都要使用一点元空间,每个线程都分配一个arena,每个都64MB,就会导致巨大的虚拟地址被分配。

6.结束语

总结一下:

·VIRT高是因为分配了太多地址空间导致。

·一般来说不用太在意VIRT太高,因为你有16EB的空间可以使用。

·如果你实在需要控制VIRT的使用,设置环境变量MALLOC_ARENA_MAX,例如hadoop推荐值为4,因为YARN使用VIRT值监控资源使用。

y原源文地址:http://www.cnblogs.com/seasonsluo/p/java_virt.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值