C/C++:进程资源限制函数(getrlimit、setrlimit)&& Shell-ulimit命令
进程在操作系统内核中是一个独立存在的运行实体。
每个进程都有 一组 资源限制,限制进程对于系统资源的申请量。
可以通过 getrlimit 来获取当前进程某一指定资源的限制。
可以通过 setrlimit 来设置当前进程某一指定资源的限制。
进程的资源限制通常是在系统初始化时由0进程建立的,然后后续进程继承。
即:进程的资源限制,是继承自fork当前进程的那个进程—父进程。
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
struct rlimit
{
lim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
从 rlimit 的结构可以看出,每个进程每种资源限制分为两种:1)硬限制;2)软限制;
在设置进程的资源限制时,有三条规则:
1)进程可以将某资源的软限制值更改为小于或等于其硬限制值;
2)任何一个进程可以降低某资源的硬限制值,但必须大于等于对应资源的软限制值,且这种“降低”对于非root用户是不可逆的;
3)只有root用户进程可以提高硬限制值;
资源限制有多种,我列举下比较常用,比较关心的几类:
RLIMIT_CORE
进程core时,core文件最大字节数(单位字节),若其值为0则不创建core文件。
RLIMIT_FSIZE
每个进程可创建的文件的最大字节长度(单位字节)。
RLIMIT_NOFILE
每个进程能打开的最大文件数目。
RLIMIT_NPROC
每个实际用户ID可拥有的最大子进程数目。
Case:列出当前进程的软硬资源限制。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#define doit(name) limit(#name, name)
static void limit(const char *name, int resource)
{
struct rlimit limit;
unsigned long long value;
if (getrlimit(resource, &limit) != 0)
{
printf("getrlimit %s = %d(%s)\n", name, errno, strerror(errno));
return;
}
printf("%-16s", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf("%-10s", "infinite");
else
{
value = limit.rlim_cur;
printf("%-10lld", value);
}
if (limit.rlim_max == RLIM_INFINITY)
printf("%-10s", "infinite");
else
{
value = limit.rlim_cur;
printf("%-10lld", value);
}
printf("\n");
}
int main()
{
#ifdef RLIMIT_CORE
doit(RLIMIT_CORE);
#else
printf("RLIMIT_CORE NOT SUPPORTED\n");
#endif
#ifdef RLIMIT_FSIZE
doit(RLIMIT_FSIZE);
#else
printf("RLIMIT_FSIZE NOT SUPPORTED\n");
#endif
#ifdef RLIMIT_NOFILE
doit(RLIMIT_NOFILE);
#else
printf("RLIMIT_NOFILE NOT SUPPORTED\n");
#endif
#ifdef RLIMIT_NPROC
doit(RLIMIT_NPROC);
#else
printf("RLIMIT_NPROC NOT SUPPORTED\n");
#endif
#ifdef RLIMIT_VMEM
doit(RLIMIT_VMEM);
#else
printf("RLIMIT_VMEM NOT SUPPORTED\n");
#endif
return 0;
}
编译 && 运行:
[jiang@localhost 0520]$ gcc -o resource resource.c
[jiang@localhost 0520]$ ./resource
RLIMIT_CORE 1048576 1048576
RLIMIT_FSIZE infinite infinite
RLIMIT_NOFILE 4096 4096
RLIMIT_NPROC 1024 1024
RLIMIT_VMEM NOT SUPPORTED
通过以上输出结果,我们可以知晓进程资源限制情况。
例如,进程的core文件限制是1024*1024=1048576字节,1024KB。
Shell内部命令—ulimit
在shell中man ulimit,可以看到ulimit的功能:
Provides control over the resources available to the shell and to processes started by it.
ulimit可以提供对shell进程本身以及由shell进程fork出来的进程的资源控制。
说到这里,我倒是想先提一下,对于shell来说,我们输入的命令分类。
第一种是外部命令。
外部命令是一个可执行文件,当我们执行外部命令时,通常是这样子的:
1)shell(记为shell-father)在终端IO操作读取外部命令的名字,然后fork出一个新的shell子进程(记为shell-son);
2)shell-son也是知道外部命令的名字的,然后shell-son执行exec系统调用,执行指定的外部命令程序;
3)shell-father在 fork shell-son 后就一直waitpid或者wait(假设外部命令启动在前台),阻塞(直到wait返回);
4)shell-son进程体(或者称为外部命令执行进程更合适)执行完毕,exit退出进程(内核发SIGCHLD给shell-father);
5)shell-father在wait到刚刚fork出的shell-son进程体,从wait/waitpid阻塞中返回,然后继续在终端进行IO操作。
注:
shell-son知道要执行的外部命令的名字,是由于shell-father在fork后,这两个进程是一样样的,父进程有的数据,子进程也有完全相同的一份;
shell-son的前三个fd,是继承自shell-father的stdin、stdout、stderr。
举个栗子:
shell-son的fd=1和shell-father的fd=1指向同一个内核中的文件表(共享偏移量等),也就是指向的是同一个文件,只不过这个文件是标准输出。
所以,当shell-son在stdout输出和shell-father在stdout输出,都是到同一个文件,即同一个终端。
第二种是内部命令。
外部命令是由当前shell执行fork并在子进程中exec执行的命令。
内部命令是由当前shell直接执行,不经过fork以及exec系统调用完成的内部操作。
常见的有cd、ulimit等命令。
shell从终端输入上读取到 cd xxx 时,shell会解析xxx为一个路径,然后修改当前shell进程的内部变量值,以完成cd操作。
ulimit命令同理。
当进程读取到ulimit命令时,将解析ulimit命令后面的参数信息,然后执行setrlimit和getrlimit操作,修改当前shell的资源限制。
我们再一次回想man手册中对ulimit的描述:
Provides control over the resources available to
the shell (内部命令,当前shell进程自身)
and to
processes started by it(外部命令,由当前shell fork出来的子进程,子进程的资源限制继承自当前shell进程).
下面简单介绍下shell ulimit内部命令。
ulimit [-SHacdefilmnpqrstuvx [limit]]
-H = hard
-S = soft
-a All current limits are reported
-c The maximum size of core files created
-f The maximum size of files written by the shell and its children
-n The maximum number of open file descriptors (most systems do not allow this value to be set)
-q The maximum number of bytes in POSIX message queues
-u The maximum number of processes available to a single user
……
Case 1:列出当前shell的资源软/硬限制
资源软限制:
[jiang@localhost ~]$ ulimit -Sa
core file size (blocks, -c) 1024
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 3810
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 1024
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
资源硬限制:
[jiang@localhost ~]$ ulimit -Ha
core file size (blocks, -c) 2048
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 3810
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 4096
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 3810
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
我们可以观察到,对于CORE文件大小,当前shell的软限制是1024,硬限制是2048。
Case 2:修改当前shell的资源软硬限制
资源硬限制:
[jiang@localhost ~]$ ulimit -Hc
2048
[jiang@localhost ~]$ ulimit -Hc 1408
[jiang@localhost ~]$ ulimit -Hc 1280
[jiang@localhost ~]$ ulimit -Hc 1152
[jiang@localhost ~]$ ulimit -Hc 1024
[jiang@localhost ~]$ ulimit -Hc 1280
-bash: ulimit: core file size: cannot modify limit: Operation not permitted
最开始,当前shell的CORE大小资源硬限制为2048,然后不断改小,设置为1408、1280、1152、1024都是可以的。
在当前shell的CORE大小资源硬限制为1024时,尝试设置其为更大的一个数值,1280,结果操作不被允许,执行失败。
硬限制只能向低的值设置,非特权用户不能提高资源硬限制值。
资源软限制:
[jiang@localhost ~]$ ulimit -Sc
1024
[jiang@localhost ~]$ ulimit -Hc
2048
[jiang@localhost ~]$ ulimit -Sc 1152
[jiang@localhost ~]$ ulimit -Sc 1280
[jiang@localhost ~]$ ulimit -Sc 1408
[jiang@localhost ~]$ ulimit -Sc
1408
[jiang@localhost ~]$ ulimit -Hc
2048
最开始当前shell的CORE资源软限制为1024,资源硬限制为2048,逐渐增大资源软限制值为1152、1280、1408。
资源软限制可以不断增大,但不能超过资源硬限制值的大小。
Case 3:资源限制在进程间的继承
Code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#define doit(name) limit(#name, name)
static void limit(const char *name, int resource)
{
struct rlimit limit;
unsigned long long value;
if (getrlimit(resource, &limit) != 0)
{
printf("getrlimit %s = %d(%s)\n", name, errno, strerror(errno));
return;
}
printf("%-16s", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf("%-10s", "infinite");
else
{
value = limit.rlim_cur;
printf("%-10lld", value);
}
if (limit.rlim_max == RLIM_INFINITY)
printf("%-10s", "infinite");
else
{
value = limit.rlim_cur;
printf("%-10lld", value);
}
printf("\n");
}
int main()
{
#ifdef RLIMIT_CORE
doit(RLIMIT_CORE);
#else
printf("RLIMIT_CORE NOT SUPPORTED\n");
#endif
return 0;
}
查看当前shell的CORE文件大小资源限制:
[jiang@localhost 0520]$ ulimit -Hc
2048
[jiang@localhost 0520]$ ulimit -Sc
1024
编译 && 执行上述程序:
[jiang@localhost 0520]$ gcc -o resource resource.c
[jiang@localhost 0520]$ ./resource
RLIMIT_CORE 1048576 1048576
在子进程中,资源软硬限制都是1024KB。
于是我猜测(注意,我没看过源码,只是实验得出的一个可能的猜测哈!):
子进程中的资源软硬限制 都是 直接继承自父进程的 软限制值 ,和父进程的 硬限制值 无关。
Case 4:修改系统配置,改变某用户对于某种资源的限制值
相关配置路径为:
/etc/security/limits.conf
[root@localhost ~]# cat /etc/security/limits.conf | grep -v "^#" | grep -v "^$"
* soft core 1024
* hard core 2048
当前配置为:任意用户的CORE文件大小硬限制为2048,软限制为1024。(单位通常为KB)
验证:
[jiang@localhost ~]$ ulimit -Hc
2048
[jiang@localhost ~]$ ulimit -Sc
1024
我想要修改用户jiang的CORE文件大小硬限制为4096,软限制为2048。
[jiang@localhost ~]$ cat /etc/security/limits.conf | grep -v "^$" | grep -v "^#"
* soft core 1024
* hard core 2048
jiang soft core 2048
jiang hard core 4096
[jiang@localhost ~]$ ulimit -Hc
4096
[jiang@localhost ~]$ ulimit -Sc
2048
修改/etc/security/limits.conf配置文件不必重启服务,当修改完并保存后自动生效。
已登录的shell(已存在的进程)是不会自动更新的,当且仅当新生成的jiang用户的shell进程会获取配置中的最新限制作为自己的资源限制值。
疑问:
我们在ulimit命令可以使用ulimited来作为一个资源的值,指代资源无限制。
但是我并未在/etc/security/limit.conf中找到类似ulimited的关键字…也就是说,我一定要给某个资源设置一个上限值?
例如,我给jiang用户设置CORE文件大小资源上限为1024KB(hard)。
我想要再次给jiang用户设置无限制无上限的值,不论是给其设置为0:
jiang hard core 0
或者注释掉这一行:
#jiang hard core 0
对于新创建的jiang的shell进程都是不起作用的,还是有一个上限值。
但是,当重启主机之后,似乎默认是jiang用户不设上限的CORE文件资源限制(hard):
[jiang@localhost ~]$ ulimit -Hc
unlimited
[jiang@localhost ~]$ ulimit -Sc
0
[jiang@localhost ~]$ ulimit -Hc unlimited
[jiang@localhost ~]$ ulimit -Hc
unlimited
有知道的小伙伴可以给我留言哈!我也多多学习下!