linux进程管理之从内存/cpu角度使用setrlimirt/rlimit
1,setrlimirt/rlimit的使用
#include <sys/resource.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>int main()
{// 设置内存限制struct rlimit rl;getrlimit(RLIMIT_AS, &rl);// 获取当前内存限制rl.rlim_cur = 1024 * 1024;// 设置软限制为1MBrl.rlim_max = 2048 * 1024;// 设置硬限制为2MBsetrlimit(RLIMIT_AS, &rl);// 应用内存限制// 内存泄露部分int *ptr;while(1){// 无限循环ptr = (int *)malloc(10000000 * sizeof(int));// 分配内存// 不释放内存,造成内存泄露printf("Allocated memory, total usage: %ld KB\n", (long)(rl.rlim_cur / 1024));sleep(1);// 休眠1秒,方便观察内存增长}return 0;
}
运行后触发oom
- OOM killer机制:
- Linux内核有OOM killer(Out Of Memory killer)机制
- 当系统内存不足时,会杀掉占用内存过多的进程
- 通过调用outofmemory()和selectbadprocess()选择一个"bad"进程杀掉
- 判断"bad"进程的标准是最占用内存的进程
-
内存泄漏导致进程挂死的机制:
- 内存泄漏会导致进程不断申请内存但不释放
- 当系统内存被耗尽时,OOM killer会杀掉这个进程
- 进程被杀后会显示为"挂死"状态
使用时需要设置相关参数
echo 2 > /proc/sys/vm/overcommit_memory
参数说明:
取值 | 模式 | 行为说明 |
---|---|---|
0 | 启发式策略(默认) | 内核估算可用内存,允许少量超量分配,但会拒绝明显无效的大内存请求 |
1 | 总是允许超量分配 | 接受所有内存申请,直到物理内存+Swap耗尽 |
2 | 严格限制超量分配 | 内存分配上限 = (物理内存 × overcommit_ratio/100) + Swap |
# 查看系统日志中的OOM Killer记录
grep "Out of memory" /var/log/messages
grep "Out of memory" /var/log/syslog
egrep -i -r 'killed process' /var/log
dmesg | grep "Out of memory"
Linux支持多种资源限制类型,主要包括:
- RLIMIT_CPU:限制进程累计CPU使用时间
- RLIMIT_FSIZE:限制文件大小
- RLIMIT_AS:限制进程地址空间大小(虚拟内存)
- RLIMIT_DATA:限制数据段大小
- RLIMIT_STACK:限制栈大小
3,栈内存泄露导致挂死问题
#include <sys/resource.h>
#include <stdio.h>void stack_overflow() {char array[1000000];// 声明一个大数组,这将耗尽栈空间printf("This will not be printed\n");
}int main()
{struct rlimit rlim;rlim.rlim_cur = 2048;// 设置栈大小限制为2048字节rlim.rlim_max = 2048;if (setrlimit(RLIMIT_STACK, &rlim) == -1) {perror("setrlimit");return 1;}stack_overflow();return 0;
}
lark@ubuntu:~$ ./rlimit_over
Segmentation fault (core dumped)lark@ubuntu:~$ dmesg | grep "rlimit_over"
[ 1211.633844] rlimit_over[2551]: segfault at 7ffe3812a070 ip 0000558d8b38f1c0 sp 00007ffe3812a070 error 6 in rlimit_over[558d8b38f000+1000]
启用CONFIG_DEBUG_STACKOVERFLOW
时,内核会在栈底设置保护页(Guard Page),触发访问时抛出SIGSEGV
信号 ,在许多系统中,栈是从高地址向低地址增长的,栈指针指向栈顶。
RLIMIT_STACK可能设置了一个最大地址,栈不能超过该地址。
因此,如果栈指针尝试移动到超过RLIMIT_STACK设置的地址以下的位置,它会触发SIGSEGV。
其他的RLIMIT_CPU,RLIMIT_FSIZE,RLIMIT_DATA使用方法类似。