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

参考

进程环境之getrlimit和setrlimit函数 | 博客园

posted @ 2021-06-06 17:50  明明1109  阅读(1473)  评论(0编辑  收藏  举报