ulimit是Shell内建指令,可用来控制shell进程或者shell子进程使用的系统资源。限制分为硬限制和软限制两种:
-H 设置硬资源限制,硬资源限制用于控制软限制。限定一旦设置只有root用户可以增加硬限制,普通用户只能减少自己的硬限制大小。
-S 设置弹性资源限制,弹性限制用于限制具体的用户或者进程。设置后普通用户可以增加,但是不能超过硬限制大小。
如果不指定-S或者-H,那么弹性资源限制和硬限制将同时设置。
例如:
| [test@debugo ~]$ ulimit -Hu 2 -bash: ulimit: max user processes: cannot modify limit: Invalid argument #因为当前弹性限制已经大于2 [test@debugo ~]$ ulimit -Su 2 [test@debugo ~]$ ulimit -Hu 2 [test@debugo ~]$ ulimit -Hu 3 -bash: ulimit: max user processes: cannot modify limit: Operation not permitted #普通用户不能增大自己的硬限制大小 [test@debugo ~]$ ulimit -Su 1 [test@debugo ~]$ ls -bash: fork: retry: Resource temporarily unavailable #打到弹性限制,限制用户使用fork()创建子进程 -bash: fork: retry: Resource temporarily unavailable ^C -bash: fork: Resource temporarily unavailable [test@debugo ~]$ ulimit -Su 2 #可以修改弹性限制到硬限制的上限,用户进程数限制为2,所以可以fork()出子进程 [test@debugo ~]$ ls #成功 |
具体资源限制类别分为:
-a 显示当前所有的limit信息。
-c core file size, 最大的转储文件大小(blocks)。如果指定为0,将不会产生core文件。
-d data seg size, 进程最大的数据段的大小(KB)。
-e scheduling priority, 进程优先级的限制:这个值对root不起作用。
-f file size, 进程可以创建的文件最大值(blocks)。
-i pending signals, 进程最大挂起/阻塞的信号量数量。
-l max locked memory, 最大可加锁的内存的大小(KB)。这个值对root用户不起作用,锁定内存的操作由mlock()函数提供,避免swap in/swap out。
-v virtual memory,进程可使用的虚拟内存上限,单位为KB。
-m max memory size, 最大内存大小(KB)。这里指的是最大物理内存
-n open files, 最大可以在进程中打开的文件数量。
-p pipe size, 管道缓冲区的大小(512 Bytes)。这个值在Linux下固定为8*512bytes。
-s stack size, 线程堆栈的上限(KB)。
-t CPU time, CPU使用时间的上限(s)。 当CPU超过这个限制时,会被KILL。
-u max user processes, 用户最多可开启的程序数目。 达到限制后fork和vfork会失败。
使用ulimit命令可以一次设置多个限制,例如ulimit -Hn 2400 -s 1024
在Oracle Enterprise Linux 6上,默认值为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$
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)
15867
max
locked
memory
(kbytes,
-l)
1048576
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
|
0. pam_limits
如果要设置ulimit资源限制永久生效,需要把修改写入/etc/security/limits.conf配置文件中。该配置文件是 Linux PAM(插入式认证模块,Pluggable Authentication Modules)中 pam_limits.so 的配置文件,这样通过ssh登录时会加载limit.conf配置,从而修改登录用户的ulimit配置。所以要使用pam_limits.so ,需要先在/etc/pam.d/system-auth中设置使用该模块,
vim /etc/pam.d/system-auth
session required pam_limits.so
而在 /etc/pam.d/sshd和/etc/pam.d/gdm中,都include了该配置文件。
session include system-auth
— required和requisite是验证的必要条件,二者的结果一样的。
然后配置/etc/security/limits.conf
格式为:
domain可以是用户或者组。如果是组的话,需要加上@符号;可以使用通配符*和%。
type可以是hard或者soft。
item是资源类别:
# – core – limits the core file size (KB)
# – data – max data size (KB)
# – fsize – maximum filesize (KB)
# – memlock – max locked-in-memory address space (KB)
# – nofile – max number of open files
# – rss – max resident set size (KB)
# – stack – max stack size (KB)
# – cpu – max CPU time (MIN)
# – nproc – max number of processes
# – as – address space limit (KB)
# – maxlogins – max number of logins for this user
# – maxsyslogins – max number of logins on the system
# – priority – the priority to run user process with
# – locks – max number of file locks the user can hold
# – sigpending – max number of pending signals
# – msgqueue – max memory used by POSIX message queues (bytes)
# – nice – max nice priority allowed to raise to values: [-20, 19]
# – rtprio – max realtime priority
例如:
所有用户都不产生core dump:
* soft core 0
ftp用户不能登录(创建shell进程)
ftp hard nproc 0
student组最大允许4个登录。
@student – maxlogins 4
1. Max locked memory
有些应用程序(如Oracle),要将内存pin到物理内存页框中避免换入/换出以提高性能。Oracle在安装的时候就需要在limit.conf中将memlock设定为一个较大的值(大于memory_target大小)
需要使用mlock()和mlockall()系统调用来实现:
mlock, munlock, mlockall, munlockall – lock and unlock memory
SYNOPSIS
#include
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
int mlockall(int flags);
int munlockall(void);
测试:
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 | #include <stdio.h> #include <sys/mman.h> int main(int argc, char* argv[]) { if (argc != 2) { perror("The parameter of size(KB) is required!"); return -1; } if (mlock((const void *)array, sizeof(array)) == -1) { perror("mlock: "); return -1; } printf("Success to lock stack mem at: %p, len=%zdn", array, sizeof(array)); if (munlock((const void *)array, sizeof(array)) == -1) { perror("munlock: "); return -1; } printf("Success to unlock stack mem at: %p, len=%zdn", array, sizeof(array)); return 0; } |
[oracle@debugo ~]$ gcc mlock.c -o mlock.o
[oracle@debugo ~]$ vim mlock.c
[oracle@debugo ~]$ ./mlock.o
Success to lock stack mem at: 0x7fff64e72e40, len=32768
Success to unlock stack mem at: 0x7fff64e72e40, len=32768
[oracle@debugo ~]$ ulimit -Sl 4
[oracle@debugo ~]$ ./mlock.o
mlock: : Cannot allocate memory #软限制设置为4B时,内存分配失败,
2. Virtual memory
virtual memory (kbytes, -v) default : unlimited
相当于limits.conf中的as和cgroup中的memory.limit_in_bytes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include
<stdio.h>
#include
<stdlib.h>
int
main(int
argc,
char*
argv[])
{
char
*p=NULL;
if
(argc
!=
2)
{
perror("The
parameter of size(KB) is required!");
return
-1;
}
printf("%sn",argv[1]);
if
(
(p
=
(char
*)malloc(1024
*
atoi(argv[1]))
)
==
NULL)
{
perror("malloc
error ");
return
-2;
}
printf("Success
to malloc memory at %pn",
p);
getchar();
free(p);
p
=
NULL;
return
0;
}
|
下面编译并验证这个virtual memory的限制:
| [oracle@debugo ~]$ gcc -o memory.c memory #分配400M内存 [oracle@debugo ~]$ ./memory 409600 409600 Success to malloc memory at 0x7fbf3d9dc010 #设置virtual memory 限制,再次执行 [oracle@debugo ~]$ ulimit -v 409599 [oracle@debugo ~]$ ./memory 409600 409600 malloc error : Cannot allocate memory |
3. Scheduling priority
在LINUX和AIX等POSIX系统中,优先级数值越小表示优先级越高,我们可以通过nice()系统调用函数或者nice命令,使用[-20, 19]中的一个数值来修改进程的nice值。这个值对root不起作用。
新的优先级 PRI(new)=PRI(old)+nice。
所以,nice值为负的时,新的优先级比原来的优先级要高。通过top命令的NI列可以看出,由于init进程的优先级0,所以它的子孙进程大部分都是0,只有少部分的内核模块进程设置为-19。
而Scheduling priority的取值范围是0-40,对应可以设定nice值的下限是0到负20。(无论何种优先级,用户都可以降低进程的优先级)
下面进行简单测试:
首先在/etc/security/limits.conf中设定:
* hard nice -20
* soft nice -20
登录任意用户(Scheduling priority的设置对root无效)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[oracle@debugo
~]$
ulimit
-Se
40
[oracle@debugo
~]$
nice
-n
-20
vim
&
[2]
19841
[oracle@debugo
~]$
nice
-n
40
vim
&
[1]
19798
[oracle@debugo
~]$
ps
-o
pid,nice
PID NI
2719
0
19694
0
19798 19 #设定大于19的nice值将nice设为19
19841
-20
然后修改/etc/security/limits.conf
*
hard nice 5
*
soft nice 5
|
登录一个非root用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [oracle@debugo Desktop]$ ulimit -Se 15 [oracle@debugo Desktop]$ nice -n -1 vim & [1] 2752 [oracle@debugo Desktop]$ nice: cannot set niceness: Permission denied [1]+ Stopped nice -n -1 vim [oracle@debugo Desktop]$ ps -o pid,nice PID NI 2709 0 2752 0 #nice值设定失败,但是进程以默认nice值运行。 2754 0 [oracle@debugo Desktop]$ nice -n 1 vim & [2] 2790 [oracle@debugo Desktop]$ ps -o pid,nice PID NI 2709 0 2752 0 2790 1 #1小于限制5,依然可以修改成功。说明Scheduling priority中0-20以及limit.conf中nice设置为0-19的效果中任何一个效果是一样的。 2792 0 |
4. CPU time
cpu time (seconds, -t) unlimited
1
2
3
4
5
6
7
8
9
10
11
12
|
#include
<stdio.h>
#include
<math.h>
int
main(int
argc,
char*
argv[])
{
double
a
=
98198192311.1;
while(1)
{
a
=
sqrt(a);
printf("%fn",
a);
}
return
0;
}
|
下面编译测试:
| [oracle@debugo Desktop]$ gcc -lm -o sqrt sqrt.c [oracle@debugo Desktop]$ ulimit -t 3 [oracle@debugo Desktop]$ ./sqrt ...... ...... 1.000000 1.000000 1.000000 Killed |
5. Open files
-n open files, 最大可以在进程中打开的文件数量。
|
[oracle@debugo
Desktop]$
ulimit
-n
1024
|
当打开文件限制为3时,cat程序打开了stdin, stdout, stderr,但是需要动态加载一个libc.so失败。
| [oracle@debugo Desktop]$ ulimit -n 3 [oracle@debugo Desktop]$ cat bash: start_pipeline: pgrp pipe: Too many open files cat: error while loading shared libraries: libc.so.6: cannot open shared object file: Error 24 |
当打开文件限制为4时,cat程序功能正常,但是管道创建失败
|
[oracle@debugo
Desktop]$
ulimit
-n
4
[oracle@debugo
Desktop]$
cat
</etc/hosts
>/tmp/hosts
bash:
start_pipeline:
pgrp
pipe:
Too
many
open
files
[oracle@debugo
Desktop]$
cat
/tmp/hosts
bash:
start_pipeline:
pgrp
pipe:
Too
many
open
files
127.0.0.1
localhost
localhost.localdomain
localhost4
localhost4.localdomain4
::1
localhost
localhost.localdomain
localhost6
localhost6.localdomain6
|
当打开文件限制为5时,管道创建正常,不会有错误提示了。
|
[oracle@debugo
Desktop]$
ulimit
-n
5
[oracle@debugo
Desktop]$
cat
/tmp/hosts
127.0.0.1
localhost
localhost.localdomain
localhost4
localhost4.localdomain4
::1
localhost
localhost.localdomain
localhost6
localhost6.localdomain6
|
^^