1. 现象

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

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值监控资源使用。

转载于:https://www.cnblogs.com/seasonsluo/p/java_virt.html

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

  1. Java进程占用内存超高分析

    Java进程占用内存超高分析_ 1. 报错 2. 解决 3. 我用到的解决方法 写了一个Java服务,没有定时服务,没有线程池,没有重度的读写,只是对外提供了几个接口,接口的访问量并不高,结果占用内存 ...

  2. 查看java进程占用内存_如何查看java进程大批占用内存

    如何查看java进程大量占用内存 你好,方法如下: 可以直接使用top命令后,查看%MEM的内容.可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令: ...

  3. Java进程占用内存过高,排查解决方法

    Java进程占用内存过高,排查解决方法 参考文章: (1)Java进程占用内存过高,排查解决方法 (2)https://www.cnblogs.com/eeexu123/p/10913389.html ...

  4. Java进程占用CPU资源过多分析

    问题描述: 生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析: 1,程序属于CPU密集型,和开发沟通 ...

  5. linux下查找java进程占用CPU过高原因

    linux下查找java进程占用CPU过高原因 1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu. 2.查找线程 使用top -H -p &l ...

  6. 趣味编程故事|java进程占用cpu过高怎么办,别急我来帮你

    关注公众号"AI码师"领取2021最新面试资料一份 [主演] 运维小哥:小李 测试小姐姐:小红 开发人员:本色出演 [剧情] 在一个阳光明媚的清晨,原本还在睡梦中的我,被小李(运维 ...

  7. 排查解决Java进程占用内存过高

    排查解决Java进程占用内存过高 1 在项目部署运行之前 1 检查JVM参数设置 2 检查代码逻辑 3 使用内存分析工具 4 检查线程 5 调整应用程序的设计 7 调整硬件资源 2 在项目部署运行之后 ...

  8. java 进程占用系统内存过高分析

    JVM的内存 先放一张JVM的内存划分图,总体上可以分为堆和非堆(粗略划分,基于java8) 那么一个Java进程最大占用的物理内存为: Max Memory = eden + survivor + ...

  9. 惊悚,单个java进程占用700%的CPU

    背景 最近负责的一个项目上线,运行一段时间后发现对应的进程竟然占用了700%的CPU,导致公司的物理服务器都不堪重负,频繁宕机. 那么,针对这类java进程CPU飙升的问题,我们一般要怎么去定位解决呢 ...

最新文章

  1. 华为4G路由器成软银快速部署宽带业务新利器
  2. java实现的代理的两种办法
  3. html怎么显示返回的图片,想要预览文件或是图片,将后端返回的信息转换为前端可以正常显示的格式...
  4. python画roc曲线需要什么数据,Python ROC曲线绘制
  5. POJ 2828 Buy Tickets(单点更新) 详细题解和思路
  6. pycharm打开cmd乱码问题
  7. JSP介绍及视频教程
  8. cookie secure
  9. 移动硬盘格式化后如何数据恢复?
  10. Windows如何关闭自动更新
  11. 在 PyCharm 中使用 PyInstaller 打包 EXE 之过程简记
  12. Linux内核详解与内核优化方案
  13. Jmeter性能测试实践--登录场景设计
  14. linux带密码解压密码,linux下解压有密码的rar压缩包
  15. Ubuntu 20.04 安装企业微信
  16. vlan绑定_华为S5700交换机设置IP-MAC绑定功能
  17. 韩版机泛泰A850改mms.apk去除收到短信的国家代码
  18. 实现直播视频app源码的底部导航栏
  19. 迭代器Iterator列表迭代器ListIterator
  20. SQL导入文本错误:大容量插入: 在数据文件中遇到意外的文件结尾 (EOF)。

热门文章

  1. Linux deepin下普通用户免密切换至root用户
  2. JVM调优:G1三色标记算法
  3. Python爬虫开发:贴吧案例
  4. Coding:在数组中查找具有给定总和的对
  5. Qt QML实现阴影字体
  6. python(numpy,pandas10)——pandas 合并数据 concat,append
  7. 记录navigator实现不同设备页面跳转
  8. python条件替换_python-根据其他列中的条件替换pandas列中的某些特定值
  9. codeforces div3 D Circular Dance (链式向前星)
  10. 关系数据库设计理论(函数依赖、异常、范式)、ER图