一个测试OOM killer的程序未触发OOM所带来的问题

概述

我们知道,由于MMU实现了虚拟地址到物理地址的转换,所以我们在申请虚拟地址时往往可以申请一大块内存,这实际上是对资源的有效利用,毕竟只有内存真正被投入使用时(如memset)才会实际分配物理内存,虚拟内存需要物理内存作为支撑,当分配了太多虚拟内存,导致物理内存不够时,就发生了Out Of Memory。

介绍下overcommit-memory机制

Linux 内核支持以下内存过度承诺处理模式:

vm.overcommit_memory = 0
启发式内存过度承诺处理。显而易见的地址空间过度承诺会被拒绝。适用于典型系统。它确保严重的过度承诺会失败,同时允许过度承诺减少交换使用量。在此模式下,root 用户可以分配略多一些内存。这是默认设置。(太明显的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存,会上报给应用程序申请失败

vm.overcommit_memory = 1
总是过度承诺。适用于某些科学应用程序。经典示例是使用稀疏数组的代码,并依赖几乎完全由零页面组成的虚拟内存。(malloc申请内存可以被申请到,但是内存耗光会触发oom killer

vm.overcommit_memory = 2
不过度承诺。系统的总地址空间承诺不得超过交换空间加上可配置数量(默认为物理内存的 50%)。根据您使用的数量,在大多数情况下,这意味着进程在访问页面时不会被杀死,但在内存分配时会适当地收到错误信息。(通过overcommit_ratio,overcommit_kbytes可以修改这个比率,来限制可以申请的内存)

适用于希望保证其内存分配将来可用而无需初始化每个页面的应用程序。
内存过度承诺策略通过 sysctl 的 vm.overcommit_memory 来设置。

过度承诺数量可以通过 vm.overcommit_ratio(百分比)或 vm.overcommit_kbytes(绝对值)来设置。

当前的过度承诺限制和已承诺的数量可以通过 /proc/meminfo 中的 CommitLimit 和 Committed_AS 查看。

接下来举个例子:
当vm.overcommit_memory = 2时;

//系统默认情况如下:
# freetotal        used        free      shared  buff/cache   available
Mem:         196732       33028      141076          60       22628      156752
Swap:             0           0           0cat /proc/meminfo | grep ommit
CommitLimit:       98364 kB
Committed_AS:       5832 kB# cat /proc/sys/vm/overcommit_ratio
50
# cat /proc/sys/vm/overcommit_memory
0
# cat /proc/sys/vm/overcommit_kbytes
0
//cat test_50M.c 申请50M空间的测试程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{long *p = NULL;while(1) {p = (long *)malloc(0x3200000);if(!p){printf("p is null\n");return 0;}memset(p, 0x55, 0x3200000);printf("50M success\n");usleep(10000);}return 0;
}
//执行,结果发现,申请第二个50M的时候申请失败
./test_50M
50M success
p is null/ # echo 30 > /proc/sys/vm/overcommit_ratio
/ # cat /proc/meminfo | grep ommit
CommitLimit:       59016 kB
Committed_AS:       5432 kB
//上述操作可以看到过度承诺的内存限制变化了,变小了/ # echo 70 > /proc/sys/vm/overcommit_ratio
/ # cat /proc/meminfo | grep ommit
CommitLimit:      137712 kB
Committed_AS:       5408 kB
/ # ./test_50M
50M success
50M success
p is null
//上述操作可以看到申请第二个50M的时候申请成功了,第三个失败了

介绍下panic_on_oom

该选项用于启用或禁用内存耗尽时的系统紧急处理功能。

  • 若设置为 0,内核将终止某些恶意进程,称为 oom_killer。通常情况下,oom_killer 能够终止恶意进程,系统将能够继续运行。
  • 若设置为 1,当内存耗尽发生时,内核会发生紧急情况。然而,如果一个进程受到内存策略/内存掩码的限制,并且这些节点出现内存耗尽状态,oom-killer 可能会终止一个进程。在这种情况下不会发生紧急情况。因为其他节点的内存可能是空闲的。这意味着系统整体状态可能还未达到灾难性程度。
  • 若设置为 2,即使在上述情况下也会强制发生内核紧急情况。即使在内存控制组下发生内存耗尽,整个系统也会发生紧急情况。

系统默认值为 0。

1 和 2 是用于集群容错的故障切换。请根据您的故障切换策略选择其中一种。
panic_on_oom=2+kdump 可以提供非常强大的工具来调查内存耗尽的原因。您可以获得快照。

介绍下oom_kill_allocating_task

该选项用于启用或禁用在内存耗尽情况下终止触发OOM的任务。

  • 若设置为零,OOM killer 将扫描整个任务列表,并根据启发式选择一个任务进行终止。通常情况下,它会选择一个占用大量内存的恶意任务,在被终止时释放大量内存。
  • 若设置为非零值,OOM killer 将直接终止触发内存耗尽条件的任务。这避免了昂贵的任务列表扫描操作。

如果选择了 panic_on_oom,它将优先于 oom_kill_allocating_task 中使用的任何值。

默认值为 0。

总结panic_on_oom和oom_kill_allocating_task关系

当系统发生OOM的时候,根据panic_on_oom配置,走系统奔溃还是杀进程
panic_on_oom=0:杀进程,此时根据oom_kill_allocating_task的配置选择进程赴死

  • oom_kill_allocating_task=0,扫描所有进程,根据算法对进程打分,分高者赴死,此时可以通过oom_score_adj选项控制进程oom_score,手动干预算法。
    早期选项(已失效):文件在/proc//oom_adj。范围是[-17 ~ 15],数值越大表示越容易被oom
    killer杀死。如果进程的oom_adj配置为-17,表示进程禁止被OOM killer杀死。
    现在选项:文件在/proc//oom_score_adj。范围是[-1000 ~ 1000],数值越大表示越容易被oom
    killer杀死。oom_score_adj=-1000,表示完全禁止进程被oom杀死。
  • oom_kill_allocating_task非0,直接杀死触发OOM的进程;

如果panic_on_oom的配置不为0,那么oom_kill_allocating_task的配置就没什么用了;

======================================================================
说了这么多我们还没有进入正题,接下来我们说下标题的问题

问题描述

测试给了一段下面的代码,说为什么没有报OOM killer

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{long *p = NULL;while(1) {p = (long *)malloc(0x3200000);usleep(10000);}return 0;
}

分析如下,我们发现内存并没有被真正的使用,印证了文章开头的一句话”只有内存真正被投入使用时(如memset)才会实际分配物理内存

/ # freetotal        used        free      shared  buff/cache   available
Mem:         196732       33084      143756          60       19892      156700
Swap:             0           0           0
/ #
/ # ./test &
/ # freetotal        used        free      shared  buff/cache   available
Mem:         196732       33676      143156          60       19900      156108
Swap:             0           0           0

修改代码为

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{long *p = NULL;while(1) {p = (long *)malloc(0x3200000);memset(p, 0x55, 0x3200000);usleep(10000);}return 0;
}

执行如下,出现了Segmentation fault,有经验的工程师就会知道可能是malloc失败,p=NULL了,memset操作空指针了,导致的Segmentation fault (core dumped)。

./test
Segmentation fault (core dumped)

在这里再转移下注意力,linux内核的core dumped如何生成和分析的,可以参考如下帖子
https://zhuanlan.zhihu.com/p/582051703
https://zhuanlan.zhihu.com/p/661430797

我们再改下代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{long *p = NULL;while(1) {p = (long *)malloc(0x3200000);if(!p){printf("p is null\n");return 0;}memset(p, 0x55, 0x3200000);usleep(10000);}return 0;
}执行结果是分配内存失败,并没有触发OOM Killer
```c
# ./test
p is null
/ # freetotal        used        free      shared  buff/cache   available
Mem:         196732       33668      155988          72        7076      156828
Swap:             0           0           0
# 介绍min_free_kbytes 
min_free_kbytes 是 Linux 内核参数,用于强制系统保持一定数量的空闲内存(以千字节为单位)。系统会根据这个数值为系统中每个低内存区域计算一个水印值(watermark)。每个低内存区域会根据其大小比例获得一定数量的保留空闲页。一定量的内存是需要用于满足 PF_MEMALLOC 分配需求的;如果将 min_free_kbytes 设置得低于 1024KB,系统可能会出现隐性问题,并在高负载下容易发生死锁。而将 min_free_kbytes 设置得过高可能会导致系统立即发生 Out Of Memory(OOM)情况。因此,在调整 min_free_kbytes 参数时,需要谨慎设置,避免设置过低导致系统问题,同时也要注意不要设置得过高导致系统内存不足。根据系统的实际情况和需求来合理配置这个参数,以确保系统的稳定性和性能表现。```c# cat /proc/sys/vm/min_free_kbytes
1771

我们按照1M内存分配,改下代码,执行发现可以触发oom killer

/ # ./test
[ 2991.645179] [King]: out_of_memory, oom_killer_disabled:0
[ 2991.650513] CPU: 1 PID: 1618 Comm: test Tainted: G           O      4.19.125 #1
[ 2991.657822] Hardware name: axera,ax620e (DT)
[ 2991.662091] Call trace:
[ 2991.664547]  dump_backtrace+0x0/0x120
[ 2991.668212]  show_stack+0x14/0x20
[ 2991.671529]  dump_stack+0x98/0xbc
[ 2991.674845]  out_of_memory+0x3c/0x350
[ 2991.678509]  __alloc_pages_nodemask+0x7cc/0x928
[ 2991.683043]  __handle_mm_fault+0x5d4/0x1058
[ 2991.687227]  handle_mm_fault+0x70/0xb8
[ 2991.690979]  do_page_fault+0x178/0x488
[ 2991.694729]  do_translation_fault+0x44/0x4c
[ 2991.698913]  do_mem_abort+0x3c/0xc8
[ 2991.702402]  el0_da+0x20/0x24
[ 2991.705448] test invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0
[ 2991.716299] CPU: 1 PID: 1618 Comm: test Tainted: G           O      4.19.125 #1
[ 2991.723619] Hardware name: axera,ax620e (DT)
[ 2991.727899] Call trace:
[ 2991.730369]  dump_backtrace+0x0/0x120
[ 2991.734048]  show_stack+0x14/0x20
[ 2991.737380]  dump_stack+0x98/0xbc
[ 2991.740708]  dump_header.isra.0+0x54/0x1f0
[ 2991.744815]  oom_kill_process+0xa8/0x484
[ 2991.748751]  out_of_memory+0x328/0x350
[ 2991.752511]  __alloc_pages_nodemask+0x7cc/0x928
[ 2991.757057]  __handle_mm_fault+0x5d4/0x1058
[ 2991.761251]  handle_mm_fault+0x70/0xb8
[ 2991.765014]  do_page_fault+0x178/0x488
[ 2991.768775]  do_translation_fault+0x44/0x4c
[ 2991.772970]  do_mem_abort+0x3c/0xc8
[ 2991.776471]  el0_da+0x20/0x24
[ 2991.779487] Mem-Info:
[ 2991.781777] active_anon:39528 inactive_anon:9 isolated_anon:0
[ 2991.781777]  active_file:32 inactive_file:48 isolated_file:0
[ 2991.781777]  unevictable:0 dirty:2 writeback:0 unstable:0
[ 2991.781777]  slab_reclaimable:1076 slab_unreclaimable:4176
[ 2991.781777]  mapped:19 shmem:18 pagetables:135 bounce:0
[ 2991.781777]  free:467 free_pcp:53 free_cma:0
[ 2991.813537] Node 0 active_anon:158112kB inactive_anon:36kB active_file:140kB inactive_file:212kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:148kB dirty:8kB writeback:0kB shmem:72kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 0kB writeback_tmp:0kB unstable:0kB all_unreclaimable? no
[ 2991.840178] Normal free:1868kB min:1768kB low:2208kB high:2648kB active_anon:158108kB inactive_anon:36kB active_file:224kB inactive_file:212kB unevictable:0kB writepending:8kB present:229108kB managed:196732kB mlocked:0kB kernel_stack:1344kB pagetables:540kB bounce:0kB free_pcp:148kB local_pcp:0kB free_cma:0kB
[ 2991.867702] lowmem_reserve[]: 0 0
[ 2991.871038] Normal: 82*4kB (UMEH) 39*8kB (UMEH) 12*16kB (UMEH) 11*32kB (UMEH) 3*64kB (MH) 2*128kB (H) 1*256kB (H) 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1888kB
[ 2991.885166] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[ 2991.893615] 100 total pagecache pages
[ 2991.897320] 57277 pages RAM
[ 2991.900125] 0 pages HighMem/MovableOnly
[ 2991.904011] 8094 pages reserved
[ 2991.907212] 0 pages hwpoisoned
[ 2991.910407] Tasks state (memory values in pages):
[ 2991.915195] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 2991.923891] [   1345]     0  1345      930       42    40960        0             0 syslogd
[ 2991.932308] [   1349]     0  1349      930       50    40960        0             0 klogd
[ 2991.941037] [   1369]     0  1369      631       31    45056        0             0 tee-supplicant
[ 2991.950091] [   1390]     0  1390      930       39    45056        0             0 crond
[ 2991.958355] [   1398]     0  1398     1721      139    53248        0         -1000 sshd
[ 2991.966529] [   1403]     0  1403      930       27    40960        0             0 telnetd
[ 2991.974959] [   1405]     0  1405      930       27    45056        0             0 ifplugd
[ 2991.983384] [   1443]     0  1443      506       32    40960        0             0 axsyslogd
[ 2991.992003] [   1447]     0  1447      506       31    40960        0             0 axklogd
[ 2992.001507] [   1449]     0  1449      930       41    40960        0             0 sh
[ 2992.009459] [   1569]     0  1569      930       30    40960        0             0 getty
[ 2992.017646] [   1618]     0  1618    39533    39059   352256        0             0 test
[ 2992.025752] Out of memory: Kill process 1618 (test) score 795 or sacrifice child
[ 2992.033157] Killed process 1618 (test) total-vm:158132kB, anon-rss:156232kB, file-rss:4kB, shmem-rss:0kB
[ 2992.065409] oom_reaper: reaped process 1618 (test), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

总结,当前内存剩余余量小于min_free_kbytes时就会触发OOM Killer,我们通过malloc 1M内存(相对小颗粒度)可以把内存耗到1771KB以下;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/724215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先 解法1 涉及到结果向上返回就要用后序遍历解法2 自己写的方法 后序遍历 ---------------&#x1f388;&#x1f388;236. 二叉树的最近公共祖先 题目链接&#x1f388;&#x1f388;-----------------…

CMake-深入理解find_package()的用法

前言&#xff1a; CMake给我们提供了find_package()命令用来查找依赖包&#xff0c;理想情况下&#xff0c;一句find_package()命令就能把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到&#xff0c;后续只管用就好了。但实际使用过程可能会出现这样那样…

SpringBoot集成flink

Flink是一个批处理和流处理结合的统一计算框架&#xff0c;其核心是一个提供了数据分发以及并行化计算的流数据处理引擎。 最大亮点是流处理&#xff0c;最适合的应用场景是低时延的数据处理。 场景&#xff1a;高并发pipeline处理数据&#xff0c;时延毫秒级&#xff0c;且兼具…

鸿蒙NEXT开发实战:【视频文件裁剪】

使用OpenHarmony系统提供的ffmpeg三方库的能力在系统中实现了音视频文件裁剪的功能&#xff0c;并通过NAPI提供给上层应用调用。 基础信息 视频文件裁剪 简介 在OpenHarmony系统整个框架中有很多子系统&#xff0c;其中多媒体子系统是OpenHarmony比较重要的一个子系统&#…

Seata 2.x 系列【1】专栏导读

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列Seata 版本 2.0.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 背景2. 简介3. 适用人群4. 环境及版本5. 文章导航5…

Spring基础——方法注入(Method Injection)

目录 查找方法注入&#xff08;Lookup Method&#xff09;查找方法注入基于XML的方法注入基于注解的方法注入 Arbitrary Method Replacement&#xff08;任意方法替换&#xff09; 文章所用项目源码参考&#xff1a;java_spring_learn_repo 查找方法注入&#xff08;Lookup Met…

解决微信好友添加频繁问题

今天我们来聊一聊微信好友添加频繁的问题。在日常使用中&#xff0c;有时候我们会遇到一些添加好友受限的情况&#xff0c;那么究竟是什么原因导致了这一问题呢&#xff1f;接下来&#xff0c;让我们逐一来看一看。 1. 添加好友的频率太高 首先&#xff0c;如果我们在短时间内…

Java必须掌握的红黑树(含面试大厂题含源码)

当面试官要求你实现一个红黑树时&#xff0c;可能会给你一些提示或者要求&#xff0c;比如要求实现插入、删除、查找等操作。下面是一个简单的红黑树实现示例&#xff0c;包含了插入操作&#xff1a; class RedBlackTree {private static final boolean RED false;private st…

.NetCore6.0实现ActionFilter过滤器记录接口请求日志

文章目录 目的实现案例&#xff1a;一.首先我们新建一个WebApi项目二.配置 appsettings.json 文件&#xff0c;配置日志存放路径三.创建 Model 文件夹&#xff0c;创建AppConfig类和ErrorLog类1.在AppConfig类中编写一个GetConfigInfo方法获取配置文件中的值2.在ErrorLog类中&a…

供应josef约瑟DL-24C电流继电器 额定电流3A 整定范围0.5-2A 电气控制必备元件

电流继电器是一种特殊的电子控制器件&#xff0c;具有控制系统和被控制系统&#xff0c;它使用较小的电流去控制较大的电流&#xff0c;起到自动开关的作用。以下是电流继电器的特征&#xff1a; 承载大电流&#xff1a;电流继电器可以承载大电流&#xff0c;通常能够承受数十…

SpringBoot集成Docker

Docker是一个开源的应用容器引擎&#xff0c;它允许开发者将应用及其依赖打包到一个可移植的容器中。 一、依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://ww…

SpringBoot 接口防刷

1&#xff1a;pom添加依赖 <dependency><groupId>net.jodah</groupId><artifactId>expiringmap</artifactId><version>0.5.10</version></dependency> 2&#xff1a;封装工具 Slf4j public class RequestUtil {/*** 1&#…

大语言模型(LLM):每个专业人士的完美助手

「大语言模型&#xff08;LLM&#xff09;革命」&#xff1a;ChatGPT如何引领工作效率新篇章 在不断发展的技术领域&#xff0c;像 ChatGPT 这样的大型语言模型 (LLM) 已成为各行业专业人士不可或缺的工具。 这篇博文探讨了大语言模型&#xff08;LLM&#xff09;在专业环境中的…

GDPU Java 天码行空2

实验2 类与封装性 文章目录 实验2 类与封装性&#xff08;一&#xff09;实验目的&#xff08;二&#xff09;实验内容和步骤&#xff08;1&#xff09;建立学生类和测试类。学生类中有成员变量&#xff1a;姓名&#xff0c;年龄&#xff1b;成员方法&#xff1a;学习&#xff…

Java 8日期时间类LocalDate、LocalDateTime详解

Java 8日期时间类LocalDate、LocalDateTime详解 一、常见类型转换1.1 LocalDateTime 转 LocalDate1.2 LocalDateTime 转 Date1.3 LocalDate 转 LocalDateTime1.4 LocalDate 转 Date1.5 Date 转 LocalDateTime1.6 Date 转 LocalDate1.7 LocalDate 转 String1.8 String 转 LocalD…

程序逻辑控制

1.java的三大结构 可以说java的这三大结构包括其中的语句跟c语言上的基本上都是一样的。现在就当重新复习一遍吧&#xff01; 1.顺序结构 2.分支结构 if语句 跟c语言的语法一模一样。就直接看文案了。 switch语句 java中的switch语句跟c语言中的switch几乎相同&#xff0c;…

AtCoder Beginner Contest 343 A~F

A.Wrong Answer&#xff08;模拟&#xff09; 题意&#xff1a; 给你两个整数 A A A和 B B B&#xff0c;它们介于 0 0 0和 9 9 9之间。 输出任何一个介于 0 0 0和 9 9 9之间且不等于 A B AB AB的整数。 分析&#xff1a; 按题意判断并输出一个整数即可。 代码&#xff…

[力扣 Hot100]Day39 对称二叉树

题目描述 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 出处 思路 每一对对称的节点AB&#xff0c;A的左儿子和B的右儿子&#xff0c;A的右儿子和B的左儿子又是一对对称节点。 代码 class Solution { public:bool compare(TreeNode* r1, TreeNode* r2){i…

qnx display

05-SA8155 QNX Display框架及代码分析(1)_openwfd-CSDN博客 backlight p: 0 t: 0 00000 SHD -----ONLINE----- 2024/03/06 13:49:22.046 backlight p:1060958 t: 1 00000 ERR backlight_be[backlight_be.c:284]: pthread_create enter 2024/03/06 13…

python基础练习题目

1. 根据身高体重&#xff0c;判断人的胖瘦 描述&#xff1a; 通过身高和体重&#xff0c;判断一个人的胖瘦。国际上一般采用BMI体重指数&#xff0c;计算公式为BMI 体重 / 身高2(保留小数点后1位)&#xff0c;参考标准如下&#xff1a;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪…