arthur-zhang / morning-up-up

78 stars 6 forks source link

1103 分享:OOM 第二部分 #6

Open arthur-zhang opened 3 years ago

arthur-zhang commented 3 years ago

主要内容:

Taaang commented 3 years ago

image

wolfleave commented 3 years ago

oom

swap

oom killer(杀高分的)

源码位置:mm/oom_kill.c

oom score决定因素:

工具

实验

实验1环境:

结果:第一个calloc进程申请成功;第二个calloc进程申请失败;

image-20201103173027404

实验2环境:

结果:第一个calloc进程申请成功;第二个calloc进程申请成功,且第一个calloc进程被杀死;

image-20201103173300897

实验3环境:

结果:前3个calloc 进程正常执行;第四个calloc进程申请内存失败;

image-20201103174704115

如果vm.overcommit_memory=1。则第四个calloc进程申请成功,且前三个calloc进程中有一个被杀死

实验4环境:

结果:进程被内核杀死

image-20201103173859941

实验5环境:

结果:申请内存失败

image-20201103174109536

LinForTracy commented 3 years ago

image

pilipala6868 commented 3 years ago

image

IKNOWLJT commented 3 years ago

swap

Linux 进程使用的内存分为以下两种

  1. 有文件背景的内存页(File-backed-page),( 代码段、mmap读写的文件等),在内存紧张的话可以写入到磁盘中,然后释放这些内存,下次访问时再从文件重新读取
  2. 没有文件背景的内存页,也叫匿名内存页(Anonymous Page), 比如 stack, malloc的内存,在内存不足的情况下,可以交换到swapfile 或者硬盘的swap区

swap 开启关闭命令(取决于时延的要求,对于redis是一定要关的,MQ这种是可以考虑开启的)

swapoff -a 关闭swap, 将不再使用内存和磁盘文件交换

swapon -a 开启swap

sar 性能监控命令 https://shockerli.net/post/linux-tool-sar/

sar -r -S 1 查看内存变化

demo 演示
#include<stdio.h>
#include<stdlib.h>

#define GB (1024 * 1024 * 1024)
#define MB (1024 * 1024)

int main (){
    size_t t = 1 * GB;
    char *array = (char *)calloc(1,t);
    if(array == NULL){
        printf("ERROR allocation fail !!!!");
        getchar();
    }else{
        printf("success %p\n",array);
        getchar();
        free(array);
    }
    return 0;
}
测试1:
环境参数:

image-20201103173509709

系统内存:1.8G 空闲:1.4G

[root@centos-7 oom]# sysctl -w vm.overcommit_memory=0
vm.overcommit_memory = 0
[root@centos-7 oom]# swapoff -a

执行上面的demo,分配内存成功

[root@centos-7 oom]# ./a.out
success 0x7f9999a97010

image-20201103173626094

开启另外的会话窗口执行上面的代码,分配失败

[parallels@centos-7 oom]$ ./a.out
ERROR allocation fail !!!!
测试2:
环境参数:

image-20201103173509709

系统内存:1.8G 空闲:1.4G

[root@centos-7 oom]# sysctl -w vm.overcommit_memory=0
vm.overcommit_memory = 1
[root@centos-7 oom]# swapoff -a

执行上面的demo,分配内存成功

会话窗口1:


[root@centos-7 oom]# ./a.out
success 0x7f9999a97010
已杀死

image-20201103173626094

开启另外的会话窗口执行上面的代码,分配成功,但是会发现会话窗口1的进程 被杀死

会话窗口2:

[parallels@centos-7 oom]$ ./a.out
success 0x7efe33981010
测试3:
环境参数:

image-20201103173509709

系统内存:1.8G 空闲:1.4G

[root@centos-7 oom]# sysctl -w vm.overcommit_memory=1
vm.overcommit_memory = 0
[root@centos-7 oom]# swapon -a

开启4个会话窗口分别执行上面的demo,前3个显示分配内存成功

前3个会话窗口:

[root@centos-7 oom]# ./a.out
success 0x7f9999a97010

开启第4个会话窗口,显示分配失败, 如下图内存变化

会话窗口4:

[parallels@centos-7 oom]$ ./a.out
success 0x7efe33981010

image-20201103181206551

总结
1. vm.overcommit_memory = 0 和 vm.overcommit_memory = 1 的区别,就是当 = 1的时候在内存不足的时候,会杀掉其他的进程用来释放内存,但是 当 = 0的时候,会在内存分配不足的时候,返回NULL,分配失败,不会干掉其他的进程
2. 当swap关闭的时候,内存不足会直接分配失败,但是当swap开启的时候会将swap区使用完才会分配失败
3. 一定要free,不然的话直接退出函数,内存会释放不掉

回收参数

vm.swappiness :决定优先回收File-backed-page,还是 Anonymous Page

vm.min_free_kbytes

OOM 测试

sysctl -w vm.overcommit_memory=1

swapoff -a

#include<stdio.h>
#include<stdlib.h>
#define GB (1024 * 1024 * 1024)
#define MB (1024 * 1024)

int main(){
    size_t t = 3L * GB;
    char *array = (char *)malloc(t);
    int i;

    for(i = 0; i < t; i++){
        if(i % (100 * MB) == 0){
            printf("allocation %d MB.....\n",(i/MB) );
        }
        array[i] = 'a';
    }
    free(array);
    getchar();
    return 0;
}

image-20201103185824261

demsg 查看OOM信息

dmesg -T

image-20201103190114487

OOM killer

决定进程杀死哪一个进程的代码逻辑被称为OOM Kiiler, 会给每个进程打分,得分被称为oom_score, Linux内存紧张的时候 OOM killer会遍历所有的进程,找到最高分数的进程将其杀掉

查看 com_score的值
cat /proc/pid/oom_score

oom_score的计算逻辑在oom_kill.c 文件中

sudo -c "echo 500 > oom_score_obj"
oom_score计分的规则:
  1. 进程rss,pagetable, swap区域的大小
  2. root特权用户进程减去3%的分数
  3. 加上oom_score_obj
oom_score_adj : 作用(重要进程给负分数)
  1. 范围 -1000 ~ 1000
  2. 查看 cat /proc/$(pidof a.out)/oom_score_adj
  3. 只能设置为改进程设置的历史oom_score_adj的最小值

image-20201103190739034

拓展命令

top :

​ e: MB 显示

​ M: 按照内存排序

Wolf-ZR commented 3 years ago

image

whx405831799 commented 3 years ago

image

wefun94 commented 3 years ago

(1)swap分区 Linux内核为了提高读写效率与速度,会将文件在内存中进行缓存,当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap分区中恢复保存的数据到内存中 (2)设置 使用free命令可以查看swap分区的大小 swapoff -a 关闭swap swapon -a 打开swap (3)开启swap后,需要进行swap分区交换,会影响系统性能,所以对于性能要求比较高的,例如http服务器等,可以选择关闭,对于对性能要求不高,或者需要保证程序可用的,可以开启swap分区 (4)命令 sar 性能监控 dmesg -T 查看内核日志 (5)OOM killer策略 linux系统会为每个进程分配一个oom_score,这个值跟内存大小有关系,也跟oom_score_adj有关系,可以通过修改oom_score_adj来修改进程的oom_score,当系统内存不足时,会优先清理oom_score分数比较大的进程