写在前面
虚拟机技术可以使得一个只有1g物理内存的机器可以运行总共需要4g内存的任务,主要方法是通过虚拟内存和物理内存映射来实现的,当物理内存不够用的时候,可以通过swap内存(存在于磁盘)和物理内存的交换来释放刚交换的物理内存,使其可以重新分配,当需要使用以前换出的内存时,在进行换入操作。
但是内存到磁盘换入换出操作十分占用CPU,因此在线上应该限制swap区的大小,如果swap占用比例较高应该进行排查和解决。
是否活跃虚拟内存大于物理内存
以jdk8为例,配置如下:
CUSTOM_JVM = -Xmx5g -Xms5g -Xmn2g -server -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+PrintCommandLineFlags -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=68 -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails
首先怀疑因为metaspace没有达到最大内存限制,因此无限增大,并且不执行fullgc,造成新分配的young对象分配时没有达到最大的NewSize,从而引起物理内存和虚拟内存的swap操作。
可以通过jstat -gccapacity pid
分析GC情况,以判断年轻代,年老代,metaspace区的晋升状态。
通过TOP命令查看内存使用情况,java进程只使用了6.5G内存,但是虚拟内存达到了13G。
Tasks: 136 total, 1 running, 135 sleeping, 0 stopped, 0 zombie
Cpu(s): 7.0%us, 3.7%sy, 0.0%ni, 88.6%id, 0.0%wa, 0.0%hi, 0.3%si, 0.4%st
Mem: 8059416k total, 7747344k used, 312072k free, 20048k buffers
Swap: 2096440k total, 1993920k used, 102520k free, 368492k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
16907 sankuai 20 0 13.0g 6.5g 6880 S 41.6 84.4 1965:06 java
5063 sankuai 20 0 1916m 24m 2884 S 6.3 0.3 171:42.18 cplugin
676 sankuai 20 0 839m 6568 1600 S 0.3 0.1 288:01.72 log_agent
9317 root 20 0 1350m 9348 2940 S 0.3 0.1 24:25.22 falcon-agent
1 root 20 0 39952 300 132 S 0.0 0.0 0:01.92 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root RT 0 0 0 0 S 0.0 0.0 0:11.90 migration/0
为什么过多的分配虚拟内存会引起swap而不会引起gc?
linux中物理内存是linux的主要内存区域,当物理内存不够时,linux会把一部分暂时不使用的内存数据放到磁盘swap区去,以便腾出更多可用内存空间。当需要使用位于swap区的数据时,必须先将其换回内存中。
整个内存区域分为:内核内存和用户内存。
虚拟内存技术给每一个进程一定虚拟内存空间,只有当虚拟内存实际被使用时,才分配物理内存,通过虚拟内存技术&