每一个进程都有一组资源限制,其中一些可以用getrlimit和setrlimit函数查询和更改。
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlim); int setrlimit(int resource, const struct rlimit *rlim); // 两个函数返回值:若成功则返回0,若出错则返回非0值
进程的资源限制通常是在系统初始化时由进程0建立的,然后由每个后续进程继承。每种实现都可以用自己的方法对各种限制做出调整。
对这两个函数的每一次调用都会指定一个资源以及一个指向下列结构的指针。有些平台定义rlimit_t为unsigned long long 而非unisgned long。
struct rlimit { rlim_t rlim_cur; /* Soft limit */ rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ };
更改资源限制时,须遵循下列三条规则:
(1) 任何一个进程都可将一个软限制更改为小于或等于其硬限制值。
(2) 任何一个进程都可降低其硬限制值,但它必须大于或等于其软限制值。这种降低对普通用户而言是不可逆的。
(3) 只有超级用户进程可以提高硬限制值。
常量RLIM_INFINITY指定了一个无限量的限制。
RLIMIT_AS 进程可用存储区的最大总长度(字节)。这会影响sbrk函数和mmap函数。
RLIMIT_CORE core文件的最大字节数,若其值为0则阻止创建core文件。
RLIMIT_CPU CPU时间的最大值(秒),当超过此软限制时,该进程发送SIGXCPU信号。
RLIMIT_DATA 数据段的最大字节长度。这是初始化数据段、非初始化以及堆的总和。
RLIMIT_FSIZE 可以创建的文件的最大字节数。当超过此软限制时,则向该进程发送SIGXFSZ信号。
RLIMIT_LOCKS (Early Linux 2.4 only) 一个进程可持有文件锁的最大数。
RLIMIT_MEMLOCK 一个进程使用mlock(2)能够锁定在存储器中的最大字节数。
RLIMIT_NOFILE 每个进程能打开的最大文件数。更改此限制将影响到sysconf函数在参数_SC_OPEN_MAX中返回的值。
RLIMIT_NPROC 每个实际用户ID可拥有的最大子进程数。更改此限制将影响到sysconf函数在参数_SC_CHILD_MAX中返回的值。
RLIMIT_RSS 最大驻内存集的字节长度。如果物理存储器供不应求,则内核将从进程取回超过RSS的部分。
RLIMIT_STACK 栈的最大字节数。
资源限制影响到调用进程并由其子进程继承。这就意味着为了影响一个用户的所有后续进程,需将资源限制的设置构造在shell之中。shell的内置命令可以查看资源限制值。
$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15843 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) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 15843 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
《UNIX环境高级编程》P166:程序清单7-8 打印当前资源限制(有改动)
#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <sys/resource.h> #define FMT "%10ld " #define doit(name) pr_limits(#name, name) static void pr_limits(char *name, int resource); int main(void) { doit(RLIMIT_AS); // 进程可用存储区的最大长度 doit(RLIMIT_CORE); // core文件的最大字节数 doit(RLIMIT_CPU); // CPU时间的最大量值 doit(RLIMIT_DATA); // 数据段的最大字节长度 doit(RLIMIT_FSIZE); // 可以创建的文件的最大字节数 doit(RLIMIT_MEMLOCK); // 一个进程使用mlock(2)能够锁定在存储器中的最大字节长度 doit(RLIMIT_NOFILE); // 每个进程能打开的最大文件数 doit(RLIMIT_NPROC); // 每个实际用户ID可拥有的最大子进程数 doit(RLIMIT_RSS); // 最大驻内存集的字节长度 doit(RLIMIT_STACK); // 栈的最大字节长度 exit(0); } static void pr_limits(char *name, int resource) { struct rlimit limit; if (getrlimit(resource, &limit) < 0) fprintf(stderr, "getrlimit error %s\n", name); printf("%-14s ", name); if (limit.rlim_cur == RLIM_INFINITY) printf("(infinite) "); else printf(FMT, limit.rlim_cur); if (limit.rlim_max == RLIM_INFINITY) printf("(infinite)"); else printf(FMT, limit.rlim_max); putchar('\n'); }
注意,在doit宏中使用了ISO C的字符串创建运算符(#),以便为每个资源名产生字符串值。例如
doit(RLIMIT_CORE);
这将由C预处理程序扩展为:
pr_limits("RLIMIT_CORE", RLIMIT_CORE);
在Ubuntu下运行此程序:
$ ./08 RLIMIT_AS (infinite) (infinite) RLIMIT_CORE 0 (infinite) RLIMIT_CPU (infinite) (infinite) RLIMIT_DATA (infinite) (infinite) RLIMIT_FSIZE (infinite) (infinite) RLIMIT_MEMLOCK 65536 65536 RLIMIT_NOFILE 1024 4096 RLIMIT_NPROC 15843 15843 RLIMIT_RSS (infinite) (infinite) RLIMIT_STACK 8388608 (infinite)