性能文章>OOM系列之八:java.lang.OutOfMemoryError: Kill process or sacrifice child>

OOM系列之八:java.lang.OutOfMemoryError: Kill process or sacrifice child转载

4月前
3494016

第一篇:java.lang.OutOfMemoryError:Java heap space

第二篇:Java.lang.OutOfMemoryError: GC overhead limit exceeded

第三篇:java.lang.OutOfMemoryError: 永久空间

第四篇:java.lang.OutOfMemoryError: 元空间

第五篇:java.lang.OutOfMemoryError: 无法创建新的本地线程

第六篇:java.lang.OutOfMemoryError: 交换空间不足

第七篇:java.lang.OutOfMemoryError: 请求的数组大小超出限制

第八篇:java.lang.OutOfMemoryError: Kill process or sacrifice child

正文:

为了理解这个错误,我们需要回顾一下操作系统的基础知识。如您所知,操作系统是建立在进程的概念之上的。这些进程由几个内核作业引导,在这种特殊情况下,我们对其中一个名为“内存不足杀手”的作业很感兴趣。

此内核作业可以在极低的内存条件下消灭您的进程。当检测到这种情况时,内存不足杀手会被激活并选择一个进程来杀死。使用一组启发式对所有进程进行评分并选择得分最差的进程来选择目标。因此,内存不足:杀死进程或牺牲子进程与我们的OOM 手册中涵盖的其他错误不同,因为它不是由 JVM 触发或代理的,而是内置于操作系统内核中的安全网。

内存不足 linux 内核

输出的存储器:杀灭过程或牺牲孩子时可用虚拟内存(包括交换)被产生误差被消耗到整个操作系统稳定性被投入风险的程度。在这种情况下,内存不足杀手会选择流氓进程并杀死它。

1,是什么原因造成的?

默认情况下,Linux 内核允许进程请求比系统中当前可用的内存更多的内存。考虑到大多数进程实际上从未使用过它们分配的所有内存,这在世界上都是有意义的。与这种方法最简单的比较是宽带运营商。他们向所有消费者出售 100Mbit 下载承诺,远远超过他们网络中的实际带宽。赌注再次取决于用户不会同时全部使用他们分配的下载限制这一事实。因此,一个 10Gbit 链路可以成功地为超过 100 个用户提供我们简单的数学所允许的服务。

如果您的某些程序正在耗尽系统内存,则这种方法的副作用是可见的。这可能导致内存极低的情况,即无法分配任何页面来处理。您可能遇到过这样的情况,即使是 root 帐户也无法杀死有问题的任务。为了防止出现这种情况,杀手会激活并识别流氓进程被杀死。

您可以在这篇来自 RedHat 文档的文章中阅读有关微调“内存不足杀手”行为的更多信息。

现在我们有了上下文,你怎么知道是什么触发了“杀手”并在凌晨 5 点叫醒你?一种常见的激活触发器隐藏在操作系统配置中。当您检查/proc/sys/vm/overcommit_memory 中的配置时,您会得到第一个提示——此处指定的值表示是否允许所有 malloc() 调用成功。请注意,proc 文件系统中参数的路径因受更改影响的系统而异。

过度使用配置允许为这个流氓进程分配越来越多的内存,这最终会触发“内存不足杀手”来做它应该做的事情。

2,举个例子

当您在 Linux 上编译并启动以下 Java 代码片段时(我使用了最新的稳定版 Ubuntu):

package eu.plumbr.demo;

public class OOM {

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[100_000_000]);
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}
}

那么您将在系统日志(在我们的示例中为/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

请注意,您可能需要调整交换文件和堆大小,在我们的测试用例中,我们使用了-Xmx2g指定的 2g 堆并具有以下交换配置:

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

 

3,解决办法是什么?

有几种方法可以处理这种情况。解决该问题的第一个也是最直接的方法是将系统迁移到具有更多内存的实例。

其他可能性包括微调 OOM 杀手、跨几个小实例水平扩展负载或减少应用程序的内存需求。

我们不热衷推荐的一种解决方案是增加交换空间。当您回忆起 Java 是一种垃圾收集语言时,此解决方案似乎已经不那么有利可图了。现代 GC 算法在物理内存中运行时是高效的,但在处理交换分配时效率受到打击。交换可以将 GC 暂停的长度增加几个数量级,因此在跳转到此解决方案之前应该三思而后行。

 

请先登录,再评论

暂无回复,快来写下第一个回复吧~

为你推荐

不起眼,但是足以让你有收获的JVM内存分析案例
分析 这个问题说白了,就是说有些int[]对象不知道是哪里来的,于是我拿他的例子跑了跑,好像还真有这么回事。点该 dump 文件详情,查看相关的 int[] 数组,点该对象的“被引用对象”,发现所
从一起GC血案谈到反射原理
前言 首先回答一下提问者的问题。这主要是由于存在大量反射而产生的临时类加载器和 ASM 临时生成的类,这些类会被保留在 Metaspace,一旦 Metaspace 即将满的时候,就会触发 Fu
关于内存溢出,咱再聊点有意思的?
概述 上篇文章讲了JVM在GC上的一个设计缺陷,揪出一个导致GC慢慢变长的JVM设计缺陷,可能有不少人还是没怎么看明白的,今天准备讲的大家应该都很容易看明白 本文其实很犹豫写不写,因为感觉没有
协助美团kafka团队定位到的一个JVM Crash问题
概述 有挺长一段时间没写技术文章了,正好这两天美团kafka团队有位小伙伴加了我微信,然后咨询了一个JVM crash的问题,大家对crash的问题都比较无奈,因为没有现场,信息量不多,碰到这类问题我
又发现一个导致JVM物理内存消耗大的Bug(已提交Patch)
概述 最近我们公司在帮一个客户查一个JVM的问题(JDK1.8.0_191-b12),发现一个系统老是被OS Kill掉,是内存泄露导致的。在查的过程中,阴差阳错地发现了JVM另外的一个Bug。这个B
JVM实战:优化我的IDEA GC
IDEA是个好东西,可以说是地球上最好的Java开发工具,但是偶尔也会卡顿,仔细想想IDEA也是Java开发的,会不会和GC有关,于是就有了接下来对IDEA的GC进行调优 IDEA默认JVM参数: -
不起眼,但是足以让你收获的JVM内存案例
今天的这个案例我觉得应该会让你涨姿势吧,不管你对JVM有多熟悉,看到这篇文章,应该还是会有点小惊讶的,不过我觉得这个案例我分享出来,是想表达不管多么奇怪的现象请一定要追究下去,会让你慢慢变得强大起来,
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得