Java基础、中级、高级、架构面试资料

Out of memory:Kill process or sacrifice child

JAVA herman 5598浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云

这个错误同样不常见,很少有人遇到,但并不代表它不存在!今天就来说说 Out of memory: Kill process or sacrifice child。

我们知道,操作系统(operating system)构建在进程(process)的基础上。进程由内核作业(kernel jobs)进行调度和维护,其中有一个内核作业称为 “Out of memory killer(OOM终结者)”。

Out of memory killer 在可用内存极低的情况下会杀死某些进程。只要达到触发条件就会激活,选中某个进程并杀掉。通常采用启发式算法,对所有进程计算评分(heuristics scoring),得分最低的进程将被 kill 掉。因此 Out of memory: Kill process or sacrifice child 和前面所讲的 OutOfMemoryError 都不同,因为它既不由JVM触发,也不由JVM代理, 而是系统内核内置的一种安全保护措施。

Out of memory: Kill process or sacrifice child

如果可用内存(含swap)不足,就有可能会影响系统稳定,这时候 Out of memory killer 就会设法找出流氓进程并杀死他,从而引起 Out of memory: kill process or sacrifice child 错误。

默认情况下,Linux kernels(内核)允许进程申请的量超过系统可用内存。这是因为,在大多数情况下,很多进程申请了很多内存,但实际使用的量并没有那么多。

打个简单的比喻:宽带租赁的服务商,可能他的总带宽只有 10Gbps,但却卖出远远超过 100 份以上的 100Mbps 带宽,原因是多数时候,宽带用户之间是错峰的, 而且不可能每个用户都用满服务商所承诺的带宽。

这样的话,可能会有一个问题,假若某些程序占用了大量的系统内存,那么可用内存量就会极小,导致没有内存页面(pages)可以分配给需要的进程。可能这时候会出现极端情况,就是 root 用户也不能通过 kill 来杀掉流氓进程。为了防止发生这种情况,系统会自动激活 killer,查找流氓进程并将其杀死。

现在我们知道了为什么会发生这种问题,那为什么是半夜5点钟触发 “killer” 发报警信息给你呢?通常触发的原因在于操作系统配置。例如:/proc/sys/vm/overcommit_memory 配置文件的值, 指定了是否允许所有的 malloc() 调用成功。请注意,在各操作系统中,这个配置对应的 proc 文件路径可能不同。

过量使用(overcommitting)配置,允许流氓进程申请越来越多的内存,最终惹得 ”Out of memory killer“ 出来搞事情。

下面我们看一个示例,产生 Out of memory: kill process or sacrifice child 错误。

public class OOM {
// 业余草:www.xttblog.com
public static void main(String[] args){
  java.util.List<int[]> l = new java.util.ArrayList();
  for (int i = 10000; i < 100000; i++) {
      try {
        l.add(new int[100000000]);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  }
}

在 Linux 上(如最新稳定版的 Ubuntu)编译并执行上面的代码,最终在系统日志中(如 /var/log/kern.log 文件)可能会看到类似下面的信息:

Jun  4 07:41:59 plumbr kernel: 
    [70667120.897649]
    Out of memory: Kill process 29957 (java) score 366 or sacrifice child
Jun  4 07:41:59 plumbr kernel: 
    [70667120.897701]
    Killed process 29957 (java) total-vm:2532680kB, anon-rss:1416508kB, file-rss:0kB

如果需要调整 swap 的大小,可以使用下面的命令:

swapoff -a 
dd if=/dev/zero of=swapfile bs=1024 count=655360
mkswap swapfile
swapon swapfile

解决这个问题的办法有多种。最简单的办法就是将系统迁移到内存更大的实例中。另外,还可以通过 OOM killer 调优,或者做负载均衡(水平扩展,集群),或者降低应用对内存的需求。

参考资料

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » Out of memory:Kill process or sacrifice child