另外参见

prlimit(1),dup(2),fcntl(2),fork(2),getrusage(2),mlock(2),mmap(2),open(2),quotactl(2),sbrk(2), shmctl(2),malloc(3),sigqueue(3),ulimit(3),core(5),功能(7),cgroups(7),凭据(7),signal(7)

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
getrlimit(),setrlimit(),prlimit()Thread safetyMT-Safe

名称

getrlimit,setrlimit,prlimit-获取/设置资源限制

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

语法

#包括
#包括

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);

glibc的功能测试宏要求(请参阅feature_test_macros(7)):

prlimit():_GNU_SOURCE

遵循规范

getrlimit(),setrlimit():POSIX.1-2001,POSIX.1-2008,SVr4、4.3BSD。

prlimit():特定于Linux。

RLIMIT_MEMLOCK和RLIMIT_NPROC从BSD派生而未在POSIX.1中指定;它们出现在BSD和Linux上,但是在其他一些实现上却没有。 RLIMIT_RSS源自BSD,并且未在POSIX.1中指定;但是,它在大多数实现中都存在。 RLIMIT_MSGQUEUERLIMIT_NICERLIMIT_RTPRIO,RLIMIT_RTTIME和RLIMIT_SIGPENDING特定于Linux。

版本

从Linux 2.6.36开始,可以使用prlimit()系统调用。从glibc 2.13开始提供库支持。

BUGS

在较早的Linux内核中,当进程遇到软性和硬性RLIMIT_CPU限制时,将传递SIGXCPU和SIGKILL信号,其发送时间应比原先晚一(CPU)。此问题已在内核2.6.8中修复。

在2.6.17之前的2.6.x内核中,RLIMIT_CPU限制为0被错误地视为"无限制"(例如RLIM_INFINITY)。从Linux 2.6.17开始,将限制设置为0确实有效,但实际上被视为1秒的限制。

内核错误意味着RLIMIT_RTPRIO在2.6.12内核中不起作用。该问题已在内核2.6.13中修复。

在内核2.6.12中,getpriority(2)和RLIMIT_NICE返回的优先级范围之间存在一对一的不匹配。其结果是尼斯值的实际上限被计算为19-rlim_cur。这已在内核2.6.13中修复。

从Linux 2.6.12开始,如果进程达到其软RLIMIT_CPU限制并为SIGXCPU安装了处理程序,则除了调用信号处理程序外,内核还会将软限制增加一秒钟。如果该进程继续消耗CPU时间,直到达到硬限制,然后终止该进程,此行为就会重复。其他实现不以这种方式更改RLIMIT_CPU软限制,并且Linux行为可能不符合标准。可移植的应用程序应避免依赖于此特定于Linux的行为。遇到软限制时,特定于Linux的RLIMIT_RTTIME限制表现出相同的行为。

当rlim-> rlim_cur大于rlim-> rlim_max时,2.4.22之前的内核无法诊断setrlimit()的错误EINVAL。

由于兼容性原因,当尝试设置RLIMIT_CPU失败时,Linux不会返回错误。

Representation of large resource limit values on 32-bit platforms

即使在32位平台上,glibc getrlimit()和setrlimit()包装函数也使用64位rlim_t数据类型。但是,在系统调用getrlimit()和setrlimit()中使用的rlim_t数据类型为(32位)无符号长。此外,在Linux中,内核将32位平台上的资源限制表示为无符号长。但是,32位数据类型不够宽。此处最相关的限制是RLIMIT_FSIZE,它指定文件可以增长到的最大大小:为了有用,此限制必须使用与表示文件偏移量的类型一样宽的类型来表示-即,与64位off_t一样宽(假定使用_FILE_OFFSET_BITS = 64编译的程序)。

要解决此内核限制,如果程序试图将资源限制设置为大于32位无符号长表示的值,则glibc setrlimit()包装函数会将限制值静默转换为RLIM_INFINITY。换句话说,所请求的资源限制设置被静默忽略。

从2.13版开始,glibc通过实现setrlimit()和getrlimit()作为调用prlimit()的包装函数,来解决getrlimit()和setrlimit()系统调用的限制。

示例

下面的程序演示了prlimit()的用法。

#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

int
main(int argc, char *argv[])
{
    struct rlimit old, new;
    struct rlimit *newp;
    pid_t pid;

    if (!(argc == 2 || argc == 4)) {
        fprintf(stderr, "Usage: %s <pid> [<new-soft-limit> "
                "<new-hard-limit>]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    pid = atoi(argv[1]);        /* PID of target process */

    newp = NULL;
    if (argc == 4) {
        new.rlim_cur = atoi(argv[2]);
        new.rlim_max = atoi(argv[3]);
        newp = &new;
    }

    /* Set CPU time limit of target process; retrieve and display
       previous limit */

    if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1)
        errExit("prlimit-1");
    printf("Previous limits: soft=%lld; hard=%lld\n",
            (long long) old.rlim_cur, (long long) old.rlim_max);

    /* Retrieve and display new CPU time limit */

    if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1)
        errExit("prlimit-2");
    printf("New limits: soft=%lld; hard=%lld\n",
            (long long) old.rlim_cur, (long long) old.rlim_max);

    exit(EXIT_SUCCESS);
}

备注

通过fork(2)创建的子进程继承其父级的资源限制。资源限制在execve(2)中保留。

资源限制是进程中所有线程共享的每个进程属性。

将资源的软限制降低到该进程当前对该资源的消耗以下将会成功(但将阻止该进程进一步增加其对资源的消耗)。

可以使用内置的ulimit命令(csh(1)中的limit)设置外壳的资源限制。 Shell的资源限制由其创建以执行命令的进程继承。

从Linux 2.6.24开始,可以通过/ proc / [pid] / limits检查任何进程的资源限制;参见proc(5)。

古代系统提供的vlimit()函数的用途与setrlimit()相似。为了向后兼容,glibc还提供了vlimit()。所有新应用程序都应使用setrlimit()编写。

C library/kernel ABI differences

从版本2.13开始,出于BUGS中所述的原因,glibc getrlimit()和setrlimit()包装函数不再调用相应的系统调用,而是使用prlimit()。

glibc包装函数的名称为prlimit();。底层系统调用是prlimit64()。

说明

getrlimit()和setrlimit()系统调用获取和设置资源限制。每个资源都有一个关联的软限制和硬限制,如rlimit结构所定义:

struct rlimit {
    rlim_t rlim_cur;  /* Soft limit */
    rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
};

软限制是内核为相应资源强制执行的值。硬限制是软限制的上限:无特权的进程只能将其软限制设置为介于0到硬限制之间的值,并(不可逆地)降低其硬限制。特权进程(在Linux下:在初始用户名称空间中具有CAP_SYS_RESOURCE功能的进程)可以对两个限制值进行任意更改。

值RLIM_INFINITY表示对资源没有限制(在getrlimit()返回的结构和传递给setrlimit()的结构中)。

resource参数必须是以下之一:

RLIMIT_AS
这是进程的虚拟内存(地址空间)的最大大小。该限制以字节为单位指定,并向下舍入为系统页面大小。此限制影响对brk(2),mmap(2)和mremap(2)的调用,这些调用在超出此限制时会失败,并显示错误ENOMEM。另外,自动堆栈扩展失败(如果没有通过sigaltstack(2)提供备用堆栈,则会生成SIGSEGV,该进程将终止该进程)。由于该值很长,因此在32位长的机器上,此限制最多为2 GB,或者此资源是无限的。
RLIMIT_CORE
这是进程可能转储的核心文件的最大大小(请参阅core(5))。如果为0,则不会创建核心转储文件。当非零时,较大的转储将被截断为此大小。
RLIMIT_CPU
这是对进程可以消耗的CPU时间量的限制(以秒为单位)。当进程达到软限制时,将发送一个SIGXCPU信号。此信号的默认操作是终止进程。但是,可以捕获信号,并且处理程序可以将控制权返回给主程序。如果该进程继续消耗CPU时间,它将每秒发送一次SI​​GXCPU,直到达到硬限制为止,然后发送SIGKILL。 (后一点描述了Linux的行为。实现方式在处理如何达到达到软限制后仍会消耗CPU时间的进程方面有所不同。需要捕获此信号的可移植应用程序应在首次收到SIGXCPU时执行有序终止。)
RLIMIT_DATA
这是进程的数据段(初始化的数据,未初始化的数据和堆)的最大大小。该限制以字节为单位指定,并向下舍入为系统页面大小。此限制影响对brk(2),sbrk(2)和(自Linux 4.7起)mmap(2)的调用,这些调用在遇到此资源的软限制时失败,并显示错误ENOMEM。
RLIMIT_FSIZE
这是该进程可能创建的文件的最大大小(以字节为单位)。尝试将文件扩展到此限制之外会导致SIGXFSZ信号的传递。默认情况下,该信号终止进程,但是进程可以捕获该信号,在这种情况下,相关的系统调用(例如write(2),truncate(2))失败,并显示错误EFBIG。
RLIMIT_LOCKS(early Linux 2.4 only)
这是此过程可能建立的flock(2)锁和fcntl(2)租约的组合数量的限制。
RLIMIT_MEMLOCK
这是可以锁定到RAM中的最大内存字节数。该限制实际上四舍五入为系统页面大小的最接近倍数。此限制影响mlock(2),mlockall(2)和mmap(2)MAP_LOCKED操作。从Linux 2.6.9开始,它还会影响shmctl(2)SHM_LOCK操作,在此操作上设置共享内存段中的总字节数的最大值(请参见shmget(2)),该最大字节数可能会被调用进程的实际用户ID锁定。 shmctl(2)SHM_LOCK锁与mlock(2),mlockall(2)和mmap(2)MAP_LOCKED建立的每个进程的内存锁分开解决;进程可以在这两个类别的每个类别中将字节锁定到此限制。
在2.6.9之前的Linux内核中,此限制控制着特权进程可以锁定的内存量。从Linux 2.6.9开始,对特权进程可以锁定的内存量没有任何限制,而是由该限制控制非特权进程可以锁定的内存量。
RLIMIT_MSGQUEUE(since Linux 2.6.8)
这是可以为调用进程的真实用户ID分配给POSIX消息队列的字节数的限制。此限制适用于mq_open(3)。用户创建的每个消息队列都将根据以下公式对这个限制进行计数(直到将其删除):
从Linux 3.5开始:
bytes = attr.mq_maxmsg * sizeof(struct msg_msg) +
                min(attr.mq_maxmsg, MQ_PRIO_MAX) *
                      sizeof(struct posix_msg_tree_node)+
                                /* For overhead */
                attr.mq_maxmsg * attr.mq_msgsize;
                                /* For message data */
Linux 3.4及更早版本:
bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
                                /* For overhead */
                attr.mq_maxmsg * attr.mq_msgsize;
                                /* For message data */
其中attr是指定为mq_open(3)的第四个参数的mq_attr结构,而msg_msg和posix_msg_tree_node结构是内核内部结构。
公式中的"开销"加数考虑了实现所需的开销字节,并确保用户不能创建无限数量的零长度消息(尽管如此,此类消息每个都消耗一些系统内存以记账)。
RLIMIT_NICE(since Linux 2.6.12, but see BUGS below)
这指定了一个上限,可以使用setpriority(2)或nice(2)将进程的nice值提高到该上限。 nice值的实际上限计算为20-rlim_cur。因此,此限制的有用范围是从1(对应于19的良好值)到40(对应于-20的良好值)。范围的这种异常选择是必要的,因为负数不能指定为资源限制值,因为它们通常具有特殊含义。例如,RLIM_INFINITY通常与-1相同。有关nice值的更多详细信息,请参见sched(7)。
RLIMIT_NOFILE
这指定的值比此过程可以打开的最大文件描述符数大一个。尝试(open(2),pipe(2),dup(2)等)超过此限制将产生错误EMFILE。 (从历史上看,此限制在BSD上称为RLIMIT_OFILE。)
从Linux 4.5开始,此限制还定义了非特权进程(不具有CAP_SYS_RESOURCE功能的进程)可以通过UNIX域套接字传递给其他进程的最大文件描述符数量。此限制适用于sendmsg(2)系统调用。有关更多详细信息,请参见unix(7)。
RLIMIT_NPROC
这是对调用进程的真实用户ID的现存进程(或更确切地说在Linux中,线程)数量的限制。只要属于该进程的真实用户ID的当前进程数大于或等于此限制,fork(2)就会失败,并显示错误EAGAIN。
对于具有CAP_SYS_ADMIN或CAP_SYS_RESOURCE功能的进程,不实施RLIMIT_NPROC限制。
RLIMIT_RSS
这是对进程的驻留集(驻留在RAM中的虚拟页数)的限制(以字节为单位)。此限制仅在Linux 2.4.x,x rlim_cur大于rlim->rlim_max。
EPERM
一个没有特权的过程试图提高硬性限制。为此需要CAP_SYS_RESOURCE功能。
EPERM
调用者尝试将硬RLIMIT_NOFILE限制增加到/ proc / sys / fs / nr_open定义的最大限制(请参阅proc(5))
EPERM
(prlimit())调用进程没有权限为pid指定的进程设置限制。
ESRCH
找不到ID为pid中指定的进程。
GETRLIMIT - Linux手册页

Linux程序员手册 第2部分
更新日期: 2020-06-09

日期:2019-08-20 17:58:51 来源:oir作者:oir