内存不足导致的应用进程被杀

内存不足导致的应用进程被杀

Scroll Down

现象

  之前碰到的一个问题。服务运行一段时间,莫名其妙挂掉,一开始以为是自己关闭了进程忘记了重启。查看日志发现最后一条日志的时间点,我并没有操作服务器。也就是说,服务是自己挂掉的。

问题排查

查看服务日志,没有任何异常。

查看/var/log/messages文件,发现其中有oom,这是被系统kill了。

Sep 18 00:08:45 vultr kernel: Out of memory: Kill process 9211 (java) score 443 or sacrifice child
Sep 18 00:08:45 vultr kernel: Killed process 9211 (java) total-vm:2185956kB, anon-rss:227232kB, file-rss:0kB, shmem-rss:0kB

手动启动服务,jps查看进程,根据进程id,top -p PID查看进程的内存占用情况,发现空闲情况下,内存占用有41%。free -h查看487M内存已使用384M,且swap为0,没有虚拟内存。

查询资料得知kernel中oom的机制:
  VM里分配不出更多的page时,就会触发oom。此时VM会调用__out_of_memory()函数,该函数会先调用select_bad_process选择一个要kill的进程,再调用oom_kill_process杀死select出来的进程。
  其中,select_bad_process函数扫描整个进程列表,为每个进程计算一个score,score最高的会被选中。

此时,真相已慢慢浮出水面。高度怀疑是服务压力增大,吃掉了内存,触发系统oom,所以被杀。

复现

接下来,尝试复现进程被杀的情况,以验证我的猜想。
  使用Jmeter,频繁调用服务内的一个查询接口。持续了没一会,Jmeter中开始出现一连串的接口调用失败。关闭Jmeter,马上jps查看进程,果然,进程没了!
  查看服务日志,还是没异常。查看/var/log/messages,出现了一个新的oom,时间吻合。

至此,问题复现。

可以得出结论:服务器内存不足导致进程被杀。

查询资料得知kernel中oom的机制:
  VM里分配不出更多的page时,就会触发oom。此时VM会调用__out_of_memory()函数,该函数会先调用select_bad_process选择一个要kill的进程,再调用oom_kill_process杀死select出来的进程。
  其中,select_bad_process函数扫描整个进程列表,为每个进程计算一个score,score最高的会被选中。

解决方案

方法一:
  可以通过设置/proc//oom_adj来调整oom_adj的值,该值会影响分数计算,oom_adj范围是[-17, 15],设为OOM_DISABLE(-17)的进程不会被oom。由于本案例中,服务器内存实在吃紧,终归还是会被杀,所以不推荐采用这种方法。

方法二:
创建swap分区,利用虚拟内存缓解压力。
1.创建swap文件,if为空字符设备,读取/dev/zero可以提供无限的空字符(NULL, ASCII NUL, 0x00),创建文件时,使用该设备进行输入,占用指定大小的空间,of为swap文件路径,bs为块大小,count为块数量。

dd if=/dev/zero of=/var/swap bs=1M count=1024

2.设置swap分区。

mkswap /var/swap

3.开启swap分区。

swapon /var/swap

4.设置开机启动swap分区。

vim /etc/fstab

文件中加入

/var/swap swap swap defaults 0 0

5.查看内存情况,发现已有swap,完成。

free -h

此后,没有再出现过进程被杀的情况,问题解决~

其他命令

删除虚拟内存

1.去除/etc/fstab中新增的内容
2.关闭虚拟内存

  // 关闭所有虚拟内存
  swapoff -a

3.删除swap文件

  rm -rf /var/swap