星空网 > 软件开发 > Java

Java 进程占用 VIRT 虚拟内存超高的问题研究

 

1. 现象

最近发现线上机器 java 8 进程的 VIRT 虚拟内存使用达到了 50G+,如下图所示:

Java 进程占用 VIRT 虚拟内存超高的问题研究

2. 不管用的 -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值监控资源使用。



原标题:Java 进程占用 VIRT 虚拟内存超高的问题研究

关键词:JAVA

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

亚马逊政策更新!两个改动让卖家抓狂:https://www.ikjzd.com/articles/130151
医疗器械出口企业注意:英国宣布不再承认CE标志,开启自己独立的认证体系:https://www.ikjzd.com/articles/130152
人人都有独立站 跨境出海必须了解的竞争策略有哪些?:https://www.ikjzd.com/articles/130154
用4个方法找出正确的亚马逊后台关键词:https://www.ikjzd.com/articles/130155
亚马逊公布20亿美元气候承诺基金的首批获得者:https://www.ikjzd.com/articles/130156
5大技巧教你优化Q4亚马逊广告:https://www.ikjzd.com/articles/130158
深圳西乡三月三北帝庙会的千岁盆菜多少钱:https://www.vstour.cn/a/365180.html
TikTok SEO:TikTok会取代谷歌吗?:https://www.kjdsnews.com/a/1836538.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流