getrlimit

nix系统函数

名称

  getrlimit,setrlimit - 控制系统资源的最大使用量。 [1] ‍‍ [2]

大纲

  #include <sys/resource.h>
  int getrlimit(int resource, struct rlimit *rlp);
  int setrlimit(int resource, const struct rlimit *rlp);

描述

  在操作系统中,我们能够通过函数getrlimit()、setrlimit()分别获得、设置每个进程能够创建的各种系统资源的限制使用量。
  调用getrlimit()或者setrlimit()来操作指定资源的操作上限。资源限制是一对值:一个指定了当前(软)限制,另一个则代表一个最大(硬)限制。软限制能够被一个进程改变,只要保证它不大于硬限制。一个进程能够(不能够撤回的)降低它的硬件限制,前提是大于等于软限制。仅当一个进程工作在一个系统超级用户权限下时能够提高它的硬件限制。调用setrlimit()来改变硬限制和软限制。限制值可能是一个“无穷大”值:RLIM_INFINITY。参数rlp是一个指向结构体rlimit的指针,该结构体包含如下成员:
  rlim_t rlim_cur; /*当前(软)限制*/
  rlim_t rlim_max; /*硬限制*/
  类型rlim_t是一个算术数据类型,等同于类型int,size_t,和off_t。
  资源限制类型概要描述如下:
  RLIMIT_CORE
  core文件的最大字节数,若其值为0则阻止创建core文件。
  RLIMIT_CPU
  CPU时间的最大量值(秒),当超过此软限制时,向该进程发送S I G X C P U信号。
  RLIMIT_DATA
  一个进程的数据段最大字节长度。数据段中初始化数据、非初始化数据以及堆的总和。当调用函数brk动态改变一个进程的数据段大小时,若失败,errno值将被设置为ENOMEM。
  RLIMIT_FSIZE
  可以创建的文件的最大字节长度。当超过此软限制时,则向该进程发送SIGXFSZ信号。
  RLIMIT_NOFILE
  每个进程能打开的最多文件数。
  RLIMIT_STACK
  栈的最大字节长度。系统不会动态增加栈的大小限制。
  在进程内部,setrlimit()将增加限制以适合您的栈大小,而不会移动当前内存段来允许增长。为了保证进程的栈能够增长,限制必须首先改变以适应运行进程使用的新栈大小。
  在一个多线程的进程中,若在线程中调用setrlimit(),而该线程不是主线程,则对于栈的限制没有任何改变。使用参数RLIMIT_STACK来调用setrlimit()仅仅能够影响主线程的栈,并且该工作本来就应该由主线程来完成。
  当超越栈大小限制时,信号SIGSEGV会发给进程。如果进程忽略该信号,或者捕捉该信号但是没有设置处理措施,该信号默认设置为SIG_DFL处理方案。
  RLIMIT_VMEM
  可映照地址空间的最大字节长度。
  RLIMIT_AS
  进程可用内存最大字节数。
  因为限制信息存储在每个进程的信息中,shell创建限制命令必须直接调用这两个系统函数来影响该shell以后创建的所有进程。
  下面资源当前限制的值会影响相对应宏定义的展开。
  限制 宏定义展开
  RLIMIT_FSIZE FCHR_MAX
  RLIMIT_NOFILE OPEN_MAX
  当使用函数getrlimit(),如果一个资源限制能够被正确赋值为类型rlim_t,则该值将被返回;否则,如果该资源限制等同于相应的硬件限制,返回值是RLIM_SAVED_MAX;否则返回值是RLIM_SAVED_CUR。
  当使用函数setrlimit(),如果请求新的限制值为RLIM_INFINITY,新的限制将是“无限制”;否则如果请求的新的限制为RLIM_SAVED_MAX,新的限制将被保存为硬件限制;如果请求的新的限制为RLIM_SAVED_CUR,新的限制将被保存为软限制;否则新的限制将赋值为请求的值。另外,如果相应传入的限制值正确,则该限制将作为新的限制值。
  设置一个限制为RLIM_SAVED_MAX或者RLIM_SAVED_CUR的结果是未知的,除非在之前调用getrlimit以了解相应的软限制或者硬限制值。
  一个限制允许其值大于RLIM_INFINITY。

返回值

  成功完成后,getrlimit()和setrlimit()返回0。否则,返回-1并设置errno指定相应错误。

错误‍

  函数getrlimit()和函数setrlimit()失败情况如下:
  EFAULT
  参数rlp指向非法地址。
  EINVAL
  指定了一个无效的资源;或者在调用函数setrlimit()时新的rlim_cur值超过了新的rlim_max值。
  EPERM
  调用函数setrlimit试图增加最大限制值,但该进程并不属于超级用户。
  函数setrlimit可能失败情况:
  EINVAL
  指定的限制值不能去减低限制值因为当前用法已经大于该指定限制值。


为了支持多用户同时登录以及多个应用连接,BSD UNIX系统给系统管理员提供了控制系统资源的许多方法。这种资源限制包括CPU时间、内存使用量以及磁盘使用量。资源控制允许你调整系统到最佳的使用率。UNIX的早期版本中,一些在编译时设置的系统限制如果需要修改,则需要重新编译整个系统。然而,如果并非所有的运行中的系统资源都需要重新编译整个系统,那么现代的BSD系统可以调整大多数这些资源的限制。

  本章阐述和进程相关的限制,包括系统端和用户使用的。我们将会看到如何发现这些限制以及怎么修改之,还将阐述进程是如何查询它的资源使用率。

7.2  确定系统限制

getrlimit,setrlimit

getrlimit允许一个进程查询所受的的系统限制.这些系统限制通过一对硬/软限制对来指定。当一个软限制被超过时,进程还可以继续,当然这取决于限制的类型,同时一个信号会发送给进程。另一方面,进程不可以超过它的硬限制。软限制值可以被进程设置在位于0和最大硬限制间的任意值。硬限制值不能被任何进程降低,仅仅超级用户可以增加之。

#include <sys/types.h>

    #include <sys/time.h>

    #include <sys/resource.h>

int   getrlimit(int resource, struct rlimit *rlp);

int   setrlimit(int resource, const struct rlimit *rlp);

getrlimit和setrlimit都使用下面的数据结构:

struct rlimit {

rlim_t rlim_cur;

rlim_t rlim_max;

};

我们来看每个成员变量。rlim_cur为指定的资源指定当前的系统软限制。rlim_max将为指定的资源指定当前的系统硬限制。

getrlimit和setrlimit函数的第一个参数是资源参数。这个参数用来指定进程获取信息的那个资源。可能的资源值列于下面。你也可以在/usr/include/sys/resource.h中找到它们:

#define   RLIMIT_CPU   0     /* cpu time in milliseconds */

RLIMIT_CPU资源限制指定一个进程可以取得CPU执行任务的毫秒数。一般地,一个进程仅仅有一个软限制而没有硬限制。如果超出软限制,进程会收到一个SIGXCPU信号。

   #define   RLIMIT_FSIZE 1     /* maximum file size */

RLIMIT_FSIZE限制指定一个进程可以创建的最大文件大小,以字节为单位。比如,如果RLIMIT_FSIZE设置为0,那么进程将根本不能创建文件。如果进程超出此限制,就会发出SIGFSZ信号。

#define   RLIMIT_DATA 2     /* data size */

RLIMIT_DATA 限制指定一个进程数据段可占据的最大字节值。一个进程的数据段就是放置动态内存的一个区域(C/C++中用malloc()分配的内存)。如果超出限制,分配新内存的操作将会遭到失败。

#define   RLIMIT_STACK 3     /* stack size */

RLIMIT_STACK限制指定进程栈可占据的最大字节数。一旦超出硬限制,进程会收到SIGSEV信号。

#define   RLIMIT_CORE 4     /* core file size */

RLIMIT_CORE限制指定了进程可以创建的最大core文件的大小。如果此限制设为0,将不能创建。另外,当达到此限制时,所有正在写core文件的进程都将被中断。

#define   RLIMIT_RSS   5     /* resident set size */

RMIMIT_RSS限制了进程的常驻集大小(resident set size)可占据的最大字节数.这个进程的常驻集和进程所使用的物理内存数有关。

   #define   RLIMIT_MEMLOCK 6     /* locked-in-memory address space */

RLIMIT_MEMLOCK限制指定了进程可以使用系统调用到mlock进行锁定的最大字节数。

   #define   RLIMIT_NPROC 7     /* number of processes */

RLIMIT_NPROC 限制指定了一个指定用户可以开启的最多并发进程数。这里的用户是通过进程来确定的有效用户ID.

#define   RLIMIT_NOFILE   8     /* number of open files */

RLIMIT_NOFILE 限制指定了进程可以打开的最多文件数。

   #define   RLIMIT_SBSIZE   9     /* maximum size of all socket buffers */

RLIMIT_SBSIZE限制指定用户在任何时刻可使用的mbufs数。可以查看socket man页来获得mbufs的定义。

#define   RLIMIT_VMEM 10 /* virtual process size (inclusive of mmap) */

RLIMIT_VMEM限制说明一个进程的映射地址空间可以占据的字节数。如果超出限制,分配动态内存和到mmap的调用会失败。

#define   RLIM_INFINITY

RLIM_INFINITY宏用来去除对一个资源的限制。换句话说,将一个资源的硬限制设置为RLIM_INFINITY将会导致此种资源的使用没有任何系统限制。 将软限制设置为RLIM_INFINITY将会阻止进程收到任何软限制警告。如果你的进程不想为那些会导致进程在超过软限制时发送信号的资源设置一个信号处理器,这个参数将变得非常有用。

如果使用了getrlimit参数,那么第二个参数需要设置为一个到rlimit结构的有效指针。然后getrlimit会将适当的限制值放入此结构。另外,在改变限制时,setrlimit会使用在第二个参数中设置值。将值设置为0将会阻止使用此资源。将值设置为RLIM_INFINITY会除去对该资源的所有限制。这些函数都在执行成功后都返回0,反之为-1.有任何错误产生,这些函数会相应的设置errno。

getpagesize函数

#include <unistd.h>

int   getpagesize(void);

  在介绍getrusage函数前,我们需要讨论一下getpagesize函数。一些进程状态 是根据使用的分页(pages)来显示的。分页的内存仅仅是一段内存,通常为4096字节左右。但是分页大小却千差万别,并且它不会固定编入(hard-coded)你的系统。取而代之的是,要确定本地系统的分页大小(pagesize)需要使用getpagesezi函数。getpagesize的返回值就是每个分页使用的字节数。

7.3 确定进程资源使用量

getrusage函数  

现在我们知道如何查看系统限制,我们还需要知道如何确定当前进程资源的使用量。getrusage函数就是用于此目的。此函数很容易被理解。一个进程可以确定它的内存使用量、CPU执行时间、甚至可获得其子进程的相关信息。因此,getrusage函数的一个用途就是帮助系统避免逃逸进程(runaway)的出现。逃逸进程指的是那些不受系统控制的进程,它们或者使用了过多的CPU(比如循环调用)、或者是超过了内存使用量的限制(导致内存泄漏)。

   #include <sys/types.h>

   #include <sys/time.h>

   #include <sys/resource.h>

  

   #define RUSAGE_SELF     0

   #define RUSAGE_CHILDREN     -1

  

int getrusage(int who, struct rusage *rusage);

getrusage函数有两个参数。第一个参数可以设置为RUSAGE_SELF或者RUSAGE_CHILDREN。如果设置成RUSAGE_SELF,那么将会以当前进程的相关信息来填充rusage(数据)结构。反之,如果设置成RUSAGE_CHILDREN,那么rusage结构中的数据都将是当前进程的子进程的信息。

rusage(数据)结构定义在/usr/include/sys/resource.h中。它含有以下成员变量:

struct rusage {

   struct timeval ru_utime; /* user time used */

   struct timeval ru_stime; /* system time used */

   long   ru_maxrss;           /* max resident set size */

   long   ru_ixrss;          /* integral shared memory size */

   long   ru_idrss;          /* integral unshared data */

   long   ru_isrss;          /* integral unshared stack */

   long   ru_minflt;           /* page reclaims */

   long   ru_majflt;           /* page faults */

   long   ru_nswap;          /* swaps */

   long   ru_inblock;       /* block input operations */

   long   ru_oublock;       /* block output operations */

   long   ru_msgsnd;           /* messages sent */

   long   ru_msgrcv;           /* messages received */

   long   ru_nsignals;       /* signals received */

   long   ru_nvcsw;          /* voluntary context switches */

   long   ru_nivcsw;           /* involuntary " */

   };

我们来详细分析每一个成员变量。

ru_utime,ru_stime

ru_utime和ru_stime成员变量包含了在用户模式和系统模式中执行时间的总和。它们都使用timeval结构(请查看前一章来了解此结构。)

ru_maxrss

ru_maxrss保存了常驻集的内存使用数。其值根据内存分页的使用来确定。

ru_ixrss

ru_ixrss值指文本段(text segment)使用的内存数乘以执行滴答数。

ru_idrss

ru_idrss 值指进程所使用的私有内存数(KB)乘以执行滴答数来。

ru_isrss

ru_isrss 指栈使用的内存数(KB为单位)乘以执行滴答数。

ru_minflt

ru_minflt值指不需要I/O的页缺失数。页缺失发生在内核需要得到一个内存页以供进程访问时。

ru_majflt

ru_majflt值指需要I/O的页缺失数。页缺失发生在内核需要得到一个内存页以供进程访问时。

ru_nswap

有时,一个进程会被调出内存,以提供空间给其他进程使用。ru_nswap指的就是一个进程将要调出内存的次数。

ru_inblock

ru_inblock 指文件系统需要为一个读请求执行输入操作的次数。

ru_oublock

ru_oublock指文件系统需要为一个写入请求执行输出操作的次数。

ru_msgsnd

ru_msgsnd指发送的IPC信息总数

ru_msgrcv

ru_msgrcv指收到的IPC信息总数。

ru_nsignals

ru_nsignals指进程收到的信号总数。

ru_nvcsw

一个进程主动上下文且混总数。主动上下文切换发生在一个进程放弃它的CPU分时时。通常发生在一个进程等待某可用资源时。

ru_nivcsw

ru_nivcsw包含了因高优先级进程运行导致的上下文切换总数。

7.4 小结

本章主要阐述了程序如何得到系统限制。这些限制不应该固定写入你的代码。取而代之的是,你的程序应该使用这些接口。这是因为这些限制是与平台相关的,甚至不同系统间都会有差别。比如,系统管理员可以调整允许打开的最大文件数,因此如果你需要增加或者减小这个值,就不能将值4096固定写入程序中。另一个例子是分页大小。一些64位系统使用8096作为默认的分页大小,但是大多数的32位系统将此默认值设置位4096。再次强调,这是个可调整的参数,不应该使用一个固定的值。

我们还学习了一个程序如何得到其资源的当前使用量,或者查看其子进程的资源使用状况。使用这些接口可以帮助我们检测甚至避免出现失控的进程。它们用在程序试图超越其软/硬限制时调试错误也非常不错。

http://baike.baidu.com/view/5048599.htm

http://blog.163.com/lijiji_1515/blog/static/1268774462009115114327206/

你可能感兴趣的:(多线程,数据结构,unix,socket,shell,struct)