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

Java 进程占用 VIRT 虚拟内存超高的问题研究的更多相关文章

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

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

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

    最近收到邮件报警,说内存使作率达到84%.如下图: 解决方法: A:可能是代码原因导致的问题: 1.使用命令:top 查看当前进程的状态 2.从上图可以看到PID:916的java进程占用内存较大.定 ...

  3. Java进程占用系统内存较高的排查方法

    1.通过top 查看具体是哪个进程占用内存较多 Tasks: 65 total, 1 running, 64 sleeping, 0 stopped, 0 zombie %Cpu(s): 2.0 us ...

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

    1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu.   2.查找线程 使用top -H -p <pid>查看线程占用情况   3. ...

  5. Java 进程占用内存过多,幕后元凶原来是线程太多

    那天中午吃饭,一个同事说,那个项目组的人快气死我了,程序有问题,早晨在群里@了他们,到中午才回消息,然后竟然还说他们的程序没有问题,是我们这边调用的太频繁了. 简直想笑. 背景说明 我们当前这个系统和 ...

  6. java进程占用系统内存高,排查解决

    转自:http://blog.51cto.com/chengxiaobai/2052530?cid=695076 故障:最近收到生产服务器的报警短信以及邮件,报警内容为:内存使用率高于70%. 使用t ...

  7. java进程占用CPU资源过高分析脚本

    #!/bin/bash #输入占用CPU较高的进程号 pid=$ if [ -z $pid ] then echo "PID is NULL" exit fi #找到该进程中占用较 ...

  8. JAVA进程占用CPU分析

    在一次生产环境中,服务器负载报警,SSH登录上看到CPU占用很高. 1.执行top命令,看到进程号为9737的进程持续占用CPU 2.怀疑是否是进程配置的内存不够了,引发了fullGC导致CPU占用高 ...

  9. jstack 排查 java 进程占用大量 CPU 问题

    1. top 看看哪个进程是罪魁祸首 2.将这个进程的jstack dump 到一个文件里面,以备使用. jstack -l 25886 > /tmp/jstack.log # 如果报错,则加 ...

随机推荐

  1. MMO之禅(三)职业能力

    MMO之禅(三)职业能力 --技术九层阶梯 Zephyr 201304 有了精神,我们还需要实际的行动. 到底需要什么能力?自我分析,窃以为为有九层,无所谓高低,因为每一层都需要不断地砥砺,编程,本身 ...

  2. Android开发中内存和UI优化

    1.内存||效率 GC这东西对于开发人员用起来比较爽,但对于技术总监或产品总监来说,他们并不在乎,在乎的是用户运行App的流畅度,待你开发完了,笑眯眯的走过来,让你测试N个适配器,烦都烦死你. 说到这 ...

  3. Android开发艺术探索笔记—— View(一)

    Android开发艺术探索笔记 --View(一) View的基础知识 什么是View View是Android中所有控件的基类.是一种界面层控件的抽象. View的位置参数 参数名 获取方式 含义 ...

  4. jquery---基本标签

    你觉得 jquery 有哪些好处? jQuery 是轻量级的 javascript 框架 强大的选择器 出色的 DOM 操作的封装 可靠的事件处理机制 完善的 ajax 封装 出色的浏览器的兼容性 支 ...

  5. WebStorm 8 注册码

    UserName:William ===== LICENSE BEGIN ===== 45550-12042010 00001SzFN0n1bPII7FnAxnt0DDOPJA INauvJkeVJB ...

  6. [IR] Ranking - top k

    PageRanking 通过: Input degree of link "Flow" model - 流量判断喜好度 传统的方式又是什么呢? Every term在某个doc中的 ...

  7. TOGAF:企业信息化复杂吗?

    本文更新版本已挪至:http://www.zhoujingen.cn/blog/2666.html -------------------- 在与人交流TOGAF的时候,离不开企业信息化,而信息化又离 ...

  8. [Solution] 一步一步WCF(2) 终结点Endpoint

    繁忙的一天又一天,不管其他,先继续WCF吧. Endpoint包含地址,绑定,契约三要素.WCF作为一个Windows平台下最大的通信框架.通过终结点承载了所有通信功能.所以终结点的作用将非常重要. ...

  9. ADO.NET---ExcuteScalar()方法复习

    ExcuteScalar(),返回的是查询结果的第一行第一列,返回值是object类型,一般用来查询表中有多少条数据,求最大值等 现在我们用ExcuteScalar()做个测试,需求:我要查询学生表里 ...

  10. CCFlow SDK模式开发

    需求: 1.业务数据要保存在我们自己的数据库里    2.CCFlow有保存草稿的功能,但是领导要求每个业务都要有草稿箱,流程从草稿箱发起,每个业务单独查询,而不要在CCFlow的统一界面查询,所以每 ...