Linux 软限制和硬限制
每个进程的实际实现都有一组资源限制, 可以用getrlimit, setrlimit获取或设置
1. getrlimit和setrlimit
getrlimit和setrlimit, 能分别获取/设置当前进程的系统资源限制
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit);
- 参数
resource 资源编号, 具体含义见下表描述
rlim 类型struct rlimit的参数, 用于记录/设置软限制(rlim_cur)和硬限制(rlim_max)
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
-
返回值
成功返回0; 失败, 返回-1, errno被设置 -
附resource所有可能取值
resource值 | 含义描述 |
---|---|
RLIMIT_AS | 进程可用存储区的最大总长度(字节)。这会影响sbrk函数和mmap函数。 |
RLIMIT_CORE | core文件的最大字节数,若其值为0, 则阻止创建core文件。 |
RLIMIT_CPU | CPU时间的最大量值(秒),当超过此软限制时,向该进程发送SIGXCPU信号。 |
RLIMIT_DATA | 数据段的最大字节长度。这是初始化数据、非初始化数据以及堆的总和。 |
RLIMIT_FSIZE | 可以创建的文件的最大字节长度。当超过此软限制时,则向该进程发送SIGXFSZ信号。 |
RLIMIT_LOCKS | 一个进程可持有的文件锁的最大数(此数也包括Linux特有的文件租借数)。 |
RLIMIT_MEMLOCK | 一个进程使用mlock(2)能够锁定在存储器中的最大字节长度。 |
RLIMIT_NOFILE | 每个进程能打开的最大文件数。更改此限制将影响到sysconf函数在参数_SC_OPEN_MAX中的返回值。 |
RLIMIT_NPROC | 每个实际用户ID可拥有的最大子进程数。更改此限制将影响到sysconf函数在参数_SC_CHILD_MAX中返回的值。 |
RLIMIT_RSS | 最大驻内存集的字节长度(resident set size in bytes, RSS)。如果物理存储器供不应求,则内核将从进程处取回超过RSS的部分。 |
RLIMIT_SBSIZE | 用户在任一给定时刻可以占用的套接字缓冲区的最大长度(字节)。(Linux 2.4.22不支持) |
RLIMIT_STACK | 栈的最大字节长度。 |
RLIMIT_VMEM | 这是RLIMIT_AS的同义词。(Linux 2.4.22不支持) |
2. 软限制和硬限制
软限制: 对进程的资源数的限制的当前值, 可用getrlimit读取, setrlimit设置, 参数struct rlimitr.lim_cur. 软限制是限制的当前值, 小于等于 硬限制, 实际进程可以调用setrlimit增长到硬限制值. 也就是说, 软限制对进程并不是真正的限制.
硬限制: 对进程的资源数的限制的最大值, 也可以用getrlimit读取/setrlimit设置, 参数struct rlimitr.rlim_max. 硬限制是绝对上限值, 进程增长资源数不会超过硬限制.
3. 实验验证
1) 以打开的文件数限制为例, 对应resource = RLIMIT_NOFILE
首先, 打印其软限制和硬限制.
然后, 通过open(O_CREAT | O_RDWR)方式打开文件, 一直到硬限制为止, 观察输出及错误情况.
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAMEMAX 100
int main()
{
struct rlimit lim;
long int i;
int fd;
char filename[FILENAMEMAX];
getrlimit(RLIMIT_NOFILE, &lim);
printf("Soft limit = %ld, Hard limit = %ld\n", lim.rlim_cur, lim.rlim_max);
for (i = 0; i < lim.rlim_max; ++i) {
snprintf(filename, sizeof(filename), "%d_%ld", getpid(), i);
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0664);
if (fd < 0) {
fprintf(stderr, "open file %s error\n", filename);
exit(1);
}
else {
printf("open file %s success\n", filename);
}
// close(fd);
}
}
输出结果见下, 可以知道成功打开了1021个文件(0~1020号), 到第1021个文件时, . 不过, 为什么不是软限制1024个呢?
因为每个进程启动的时候, 已经默认打开了stdin, stdout, stderr这3个文件.
Soft limit = 1024, Hard limit = 4096
open file 17921_0 success
open file 17921_1 success
open file 17921_2 success
open file 17921_3 success
...
open file 17921_1018 success
open file 17921_1019 success
open file 17921_1020 success
open file 17921_1021 error
2) 在1)的基础上, 修改软限制, 使软限制 = 硬限制
在printf和for之间, 添加setrlimit语句, 修改软限制
getrlimit(RLIMIT_NOFILE, &lim);
printf("Soft limit = %ld, Hard limit = %ld\n", lim.rlim_cur, lim.rlim_max);
/* 修改软限制 */
lim.rlim_cur = lim.rlim_max;
setrlimit(RLIMIT_NOFILE, &lim);
for (i = 0; i < lim.rlim_max; ++i) {
...
}
再次运行, 程序可以打开4096个文件(包括stdin/stdout/stdout 3个文件)
...
open file 19449_4090 success
open file 19449_4091 success
open file 19449_4092 success
open file 19449_4093 error