rlimit 介绍
在Linux中,对进程的限制有多种,如ulimit、rlimit、cgroup等。ulimit为shell层对进程的限制,rlimit为程序中限制单进程的资源使用,cgroup则非限制单进程资源,而是限制了一组进程的资源使用,Docker就是cgroup的经典使用场景。这篇文章主要介绍了rlimit的相关参数,setrlimit getrlimit的使用方式,一个使用rlimit限制进程的demo。
在Linux环境编程下,我们可以具体的限制一个进程对资源的使用,当进程尝试超过资源使用的限制,它可能会收到一个信号,或是因资源超限而失败的系统调用。每个进程最初的获得的限制来自父进程,但是后来可以更改这个限制。
两个关于资源限制的概念
current limit
为系统规定的上限,也叫做”soft limit”,因为进程通常将被限制在这个范围内。
maxinum limit
为一个进程被允许建立current limit的最大值,也叫做”hard limit”,因为一个进程无法避开它,一个进程低于他自己的maxinum limit,且只有超级用户可能提高它的maxinum limit。
1 2 3 4 5 |
struct rlimit { rlim_t rlim_cur; //The current limit rlim_t rlim_max; //The maximum limit. }; |
使用getrlimit,setrlimit,getrlimit64,setrlimit64(定义在<sys/resource.h>)进行对rlimit结构的使用。
1 2 3 4 5 6 7 8 9 |
— Function: int getrlimit (int resource, struct rlimit *rlp) 读取类型为resource的限制值,并储存在rlp中。 返回值为0时成功,-1时失败。失败时可能将errno设置为DEFAULT. — Function: int setrlimit (int resource, const struct rlimit *rlp) 更新新的current limit 与 maxinum limit限制 ,参数resource为限制的类型(下方有参数表),*rlp带更新的结构体。 同样成功返回0,失败返回-1.将errno设置为EPERM有如下两种情况: 1.设置的current limit 超过了maxinum limit的值。 2.在不是超级用户的情况下设置了maxinum limit。 |
进程资源限制的种类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
RLIMIT_CPU CPU使用时间限制,如果运行时间长于该值,将会收到信号:SIGXCPU 该值以秒计量。 RLIMIT_FSIZE 进程可创建文件大小限制,如果进程尝试写更大的文件将会受到信号:SIGXFSZ RLIMIT_DATA 最大内存使用限制,如果进程尝试分配内存并超出这个范围,分配函数将会失败。 RLIMIT_STACK 进程使用栈的大小限制,如果进程尝试扩展它的栈并超过这个值,那个会收到信号SIGSEGV RLIMIT_CORE 进程创建core文件大小限制,如果进程结束并且要存储core文件高于该值,那么core文件不会被创建,所以设置这个值为0回保证core文件从不被创建。 RLIMIT_RSS 进程所能得到的最大物理内存,这个参数是系统调度程序和内存分配的向导,系统在有盈余时将会。给进程更多的内存 RLIMIT_MEMLOCK 在物理内存中最大被锁内存数。 RLIMIT_NPROC 同一用户ID创建最大进程数,如果已经到达最大进程数再调用fork会失败。 RLIMIT_NOFILERLIMIT_OFILE 进程可开最大文件数,如果超出最大数将会失败,该值存在在GNU 和 4.4BSD,部分系统没有。 RLIMIT_AS 进程总共可获得的最大内存数,如果进程尝试分配更多内存,那么分配函数将会失败。 RLIM_NLIMITS 所有参数值的限制,以上任何参数值都不能高于该值。 — Constant: rlim_t RLIM_INFINITY 在调用setrlimit的时候该常量被定义为无穷 |
rlimit 使用 Demo
用C写了一个demo,用getopt函数把资源限制项做成参数,编译后执行相关binary时可以起到限制作用,具体细节见代码。
limit.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <sys/time.h> #include <sys/resource.h> #include <unistd.h> #ifndef _LIMIT_H_ #define _LIMIT_H_ typedef struct { int option; /* The ulimit option for this limit. */ int parameter; /* Parameter to pass to get_limit (). */ int block_factor; /* Blocking factor for specific limit. */ char *description; /* Descriptive string to output. */ char *units; /* scale */ } RESOURCE_LIMITS; static RESOURCE_LIMITS limits[] = { { 'c', RLIMIT_CORE, 1024, "core file size","kbytes" }, { 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" }, { 'f', RLIMIT_FSIZE, 1024, "file size", "kbytes" }, { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" }, { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" }, { 'n', RLIMIT_NOFILE, 1, "open files", (char *) NULL }, { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" }, { 't', RLIMIT_CPU, 1, "cpu time", "seconds" }, { 'u', RLIMIT_NPROC, 1, "max user processes", (char *) NULL }, { 'v', RLIMIT_AS, 1024, "virtual memory", "kbytes" }, { 'x', RLIMIT_LOCKS, 1, "max file locks", (char *) NULL }, { -1, -1, -1, (char *) NULL, (char *) NULL } }; #define NCMDS (sizeof(limits) / sizeof(limits[0])) #endif |
limit.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include "limit.h" #define MAX_ARGS 64 extern char **environ; void usage(char* progname) { int i; printf( "Usage: %s [option] \"[command [arg ...]]\" [redirection information]\n" "option:\n", progname); for (i = 0; limits[i].option > 0; i++) { char unitstr[64]; if (limits[i].units) sprintf(unitstr, "(%s, -%c) ", limits[i].units, limits[i].option); else sprintf(unitstr, "(-%c) ", limits[i].option); printf("\t%-18s %16s\n", limits[i].description, unitstr); } exit(-1); } static int findlim(int opt) { register int i; for (i = 0; limits[i].option > 0; i++) if (limits[i].option == opt) return i; return -1; } static int setlimit(int type, struct rlimit* limit) { int err; if (limit == NULL) return -1; if (type > 12) //kernel support rlimit from 0 to 12 return -1; err = setrlimit(type, limit); if (err < 0) { perror("setrlimit faild:"); } return err; } /*Main entry*/ int main(int argc, char** argv) { int ch, i; int softflag = 0, hardflag = 0; char* cmd = NULL; int do_flags[NCMDS]; int values[NCMDS]; memset(do_flags, 0, sizeof(int) * NCMDS); memset(values, 0, sizeof(int) * NCMDS); if (argc < 3 || argv[1][0] != '-') usage(argv[0]); opterr = 0; while ((ch = getopt(argc, argv, "SHc:d:f:l:m:n:s:t:u:v:x:")) != -1) { switch (ch) { case 'S': softflag = 1; break; case 'H': hardflag = 1; break; case 'c': case 'd': case 'f': case 'l': case 'm': case 'n': case 's': case 't': case 'u': case 'v': case 'x': { int index = findlim(ch); do_flags[index] = 1; values[index] = atoi(optarg); break; } default: usage(argv[0]); } } if ((argc - optind) != 1) usage(argv[0]); cmd = argv[optind]; for (i = 0; limits[i].option > 0; i++) { if (do_flags[i] == 1) { struct rlimit limit; long rlimitvalue = ((long) values[i]) * limits[i].block_factor; int err; if (hardflag == softflag) limit.rlim_cur = limit.rlim_max = rlimitvalue; else if (hardflag > 0) limit.rlim_max = rlimitvalue; else limit.rlim_cur = rlimitvalue; err = setlimit(limits[i].parameter, &limit); if (err < 0) { perror("Setrlimit Faild: "); printf("\n"); } } } if (NULL == cmd) { printf("limit: error cmd\n"); usage(argv[0]); } const char *new_argv[4]; new_argv[0] = "sh"; new_argv[1] = "-c"; new_argv[2] = cmd; new_argv[3] = NULL; (void) execve("/bin/sh", (char * const *) new_argv, environ); _exit(127); return 0; } |
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
LIBPATH=../../../../ INC=-I./ LIB=-L./ CFLAGS= $(INC) -g -Wall CC = gcc .c.o: $(CC) $(CFLAGS) -c $^ rebuild:clean all EXE = limitp SCRIPTS = all : $(EXE) $(SCRIPTS) notime : all ${EXE}:limit.c $(CC) $(CFLAGS) -o $@ $^ $(LIB) clean : rm -rf $(EXE) rm -rf *.o |
测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdio.h> #include <string.h> char a[1000000]; int main() { printf("now using heap memory.\n"); int num = 0; memset(a,0,sizeof(a)); char *b = (char *)malloc (1<<10); memset(b,0,sizeof(b)); return 0; } |
运行shell:
1 2 3 4 5 |
$ ./limitp -m 10 -v 10 "./test" 已杀死 $ ./test now using heap memory. |