Swap
1. 什么是Swap
swap 是把一块磁盘空间或者一个本地文件当做内存来使用。可用内存无法满足内存分配请求的时候,把不常用的内存数据存储到磁盘,并在内存中释放这部分内存。当进程再次访问这部分内存的时候,再读取到内存中来。
2. 为什么要有swap
os面对物理内存申请不足的时候,一种方法是oom,另一种方法是回收内存。
内存回收也分成2种,一种就是直接回收,另一种是定期回收,swap就是定期回收的一种
所以,swap的出现主要是解决内存不足
3. 对于gc有没有影响
如果java进程用到了swap内存,那么在gc的时候是会有影响的,毕竟涉及到磁盘写入和读取,且这个是由os控制。换入到磁盘的是冷数据,那应该也就影响Full GC,由于内存不足导致的频繁清理也会影响Minor GC(猜的)。
出现这种问题最大的问题还是物理内存不足以满足进程所需内存。所以应该把着重点放在进程所需内存调整和物理内存扩容这两点上。
4. swap大致运行逻辑
前面提到os在回收内存有两种方式,一种就是直接回收,另一种是定期回收。定期回收由专门的内核线程来进行回收。
当 pages_min<剩余内存<pages_low,线程就会执行内存回收。
可以通过cat /proc/zoneinfo
查看。
回收模式可以通过cat /proc/sys/vm/zone_reclaim_mode
查看。
- 0 意味着关闭zone_reclaim模式,可以从其他zone回收内存
- 1 表示打开zone_reclaim模式,这样内存回收只会发生在本地节点内
- 2 在本地回收内存时,可以将cache中的脏数据写回硬盘,以回收内存。
- 4 可以用swap方式回收内存。
简单实验
环境准备
- 开启Swap
shell
# 创建Swap文件
$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置Swap文件
$ mkswap /mnt/swapfile
# 开启Swap
$ swapon /mnt/swapfile
# 关闭Swap
$ swapoff -a
- java文件准备
java
import java.lang.ref.SoftReference;
class FullGCTest {
public static void main(String[] args) {
SoftReference<byte[]>[] list=new SoftReference[1000];
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
list[i]= new SoftReference<>(new byte[1024 * 1024 * 10]);
}
System.out.println("程序执行完毕");
}
}
- 启动命令
ruby
# Xms Xmx我这选择用的就是free的值
java -XX:+PrintGCDetails -Xms1398m -Xmx1398m -XX:SurvivorRatio=8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC FullGCTest
-
gc情况查看(看日志也行) 具体参数和其他命令可以参考:JVM命令行调优工具备忘录
jstat -gc 15198 100
-
清空缓存
bash
sudo echo 3 > /proc/sys/vm/drop_caches
Swap未开启
当内存快满的时候,并未有明显的时间家具
Swap开启
加大堆内存
java -XX:+PrintGCDetails -Xms4096m -Xmx4096m -XX:SurvivorRatio=8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC FullGCTest
不太精确的总结
- 前面2个对照组,当没有使用到swap空间的时候,gc时间差不多,当swap空间使用的时候,会有一个明显的增加
- 最后一个是模拟大量使用swap的场景,gc时间都有一个明显的增加
- 当然也可能和我阿里云服务器1核2G有关,又分配了4G的堆内存。
- gc属于java进程管理,swap属于os管理。影响应该是有的,但是两者都不可控,不应该纠结于swap,而是研究物理内存是否充足,java进程分配是否合理
以上来自一次真实的生产事故排查