这是一篇非常好的文章,对ulimit的各个限制参数讲得非常透彻。原文链接:http://home.lupaworld.com/home-space-uid-56821-do-blog-id-232810.html

一般可以通过ulimit命令或编辑/etc/security/limits.conf重新加载的方式使之生效



通过ulimit比较直接,但只在当前的session有效,limits.conf中可以根据用户和限制项使用户在下次登录中生效.



对于limits.conf的设定是通过pam_limits.so的加载生效的,比如/etc/pam.d/sshd,这样通过ssh登录时会加载limit.

又或者在/etc/pam.d/login加载生效.



下面将对各种限制进行分析



core file size          (blocks, -c) 0

data seg size           (kbytes, -d) unlimited

scheduling priority             (-e) 20 a

file size               (blocks, -f) unlimited a

pending signals                 (-i) 16382

max locked memory       (kbytes, -l) 64 a

max memory size         (kbytes, -m) unlimited a

open files                      (-n) 1024 a

pipe size            (512 bytes, -p) 8

POSIX message queues     (bytes, -q) 819200

real-time priority              (-r) 0

stack size              (kbytes, -s) 8192

cpu time               (seconds, -t) unlimited

max user processes              (-u) unlimited

virtual memory          (kbytes, -v) unlimited

file locks                      (-x) unlimited





一)限制进程产生的文件大小(file size)



先来说说ulimit的硬限制和软限制

硬限制用-H参数,软限制用-S参数.

ulimit -a看到的是软限制,通过ulimit -a -H可以看到硬限制.

如果ulimit不限定使用-H或-S,此时它会同时把两类限制都改掉的.

软限制可以限制用户/组对资源的使用,硬限制的作用是控制软限制.

超级用户和普通用户都可以扩大硬限制,但超级用户可以缩小硬限制,普通用户则不能缩小硬限制.

硬限制设定后,设定软限制时只能是小于或等于硬限制.







下面的测试应用于硬限制和软限制.





1)软限制不能超过硬限制

在超级用户下,同时修改硬/软限制,使当前会话只能建100KB的文件

ulimit -f 100



查看当前创建文件大小的硬限制为100KB

ulimit -H -f

100



此时限制当前会话的软限制为1000KB,出现不能修改的报错

ulimit -S -f 1000

-bash: ulimit: file size: cannot modify limit: Invalid argument





2)硬限制不能小于软限制

在超级用户下,用户查看当前的软限制,此时为unlmiited

ulimit -S -f

unlimited



此时修改当前会话创建文件大小的硬限制为1000KB,出现不能修改的报错,说明硬限制不能小于软限制

ulimit -H -f 1000

-bash: ulimit: file size: cannot modify limit: Invalid argument



如果我们把创建文件大小的软限制改为900KB,此后就可以修改它的硬限制了

ulimit -S -f 900

ulimit -H -f 1000





3)普通用户只能缩小硬限制,超级用户可以扩大硬限制



用普通用户进入系统

su - test



查看创建文件大小的硬限制

ulimit -H -f

unlimited



此时可以缩小该硬限制

ulimit -H -f 1000





但不能扩大该硬限制

ulimit -H -f 10000





4)硬限制控制软限制,软限制来限制用户对资源的使用



用软限制限制创建文件的大小为1000KB

ulimit -S -f 1000



用硬限制限制创建文件的大小为2000KB

ulimit -H -f 2000



创建3MB大小的文件

dd if=/dev/zero of=/tmp/test bs=3M count=1

File size limit exceeded



查看/tmp/test的大小为1000KB,说明软限制对资源的控制是起决定性作用的.

ls -lh /tmp/test

-rw-r--r-- 1 root root 1000K 2010-10-15 23:04 /tmp/test





file size单位是KB.





二)关于进程优先级的限制(scheduling priority)

这里的优先级指NICE值

这个值只对普通用户起作用,对超级用户不起作用,这个问题是由于CAP_SYS_NICE造成的.

例如调整普通用户可以使用的nice值为-10到20之间.

硬限制nice的限制为-15到20之间.

ulimit -H -e 35



软限制nice的限制为-10到20之间

ulimit -S -e 30



用nice命令,使执行ls的nice值为-10

nice -n -10 ls /tmp

ssh-BossiP2810  ssh-KITFTp2620  ssh-vIQDXV3333



用nice命令,使执行ls的nice值为-11,此时超过了ulimit对nice的软限制,出现了异常.

nice -n -11 ls /tmp

nice: cannot set niceness: Permission denied





三)内存锁定值的限制(max locked memory)

这个值只对普通用户起作用,对超级用户不起作用,这个问题是由于CAP_IPC_LOCK造成的.

linux对内存是分页管理的,这意味着有不需要时,在物理内存的数据会被换到交换区或磁盘上.

有需要时会被交换到物理内存,而将数据锁定到物理内存可以避免数据的换入/换出.

采用锁定内存有两个理由:

1)由于程序设计上需要,比如oracle等软件,就需要将数据锁定到物理内存.

2)主要是安全上的需要,比如用户名和密码等等,被交换到swap或磁盘,有泄密的可能,所以一直将其锁定到物理内存.



锁定内存的动作由mlock()函数来完成

mlock的原型如下:

int mlock(const void *addr,size_t len);



测试程序如下:

#include <stdio.h>

#include <sys/mman.h>



int main(int argc, char* argv[])

{

        int array[2048];



        if (mlock((const void *)array, sizeof(array)) == -1) {

                perror("mlock: ");

                return -1;

        }



        printf("success to lock stack mem at: %p, len=%zd\n",

                        array, sizeof(array));





        if (munlock((const void *)array, sizeof(array)) == -1) {

                perror("munlock: ");

                return -1;

        }



        printf("success to unlock stack mem at: %p, len=%zd\n",

                        array, sizeof(array));



        return 0;

}



gcc mlock_test.c -o mlock_test



上面这个程序,锁定2KB的数据到物理内存中,我们调整ulimit的max locked memory.

ulimit -H -l 4

ulimit -S -l 1

./mlock_test

mlock: : Cannot allocate memory



我们放大max locked memory的限制到4KB,可以执行上面的程序了.

ulimit -S -l 4

./mlock_test

success to lock stack mem at: 0x7fff1f039500, len=2048

success to unlock stack mem at: 0x7fff1f039500, len=2048



注意:如果调整到3KB也不能执行上面的程序,原因是除了这段代码外,我们还会用其它动态链接库.





四)进程打开文件的限制(open files)




这个值针对所有用户,表示可以在进程中打开的文件数.



例如我们将open files的值改为3

ulimit -n 3



此时打开/etc/passwd文件时失败了.

cat /etc/passwd

-bash: start_pipeline: pgrp pipe: Too many open files

-bash: /bin/cat: Too many open files







五)信号可以被挂起的最大数(pending signals)



这个值针对所有用户,表示可以被挂起/阻塞的最大信号数量



我们用以下的程序进行测试,源程序如下:



#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <signal.h>

#include <unistd.h>



volatile int done = 0;



void handler (int sig)

{

  const char *str = "handled...\n";

  write (1, str, strlen(str));

  done = 1;

}



void child(void)

{

  int i;

  for (i = 0; i < 3; i++){

    kill(getppid(), SIGRTMIN);

    printf("child - BANG!\n");

  }

  exit (0);

}



int main (int argc, char *argv[])

{

  signal (SIGRTMIN, handler);

  sigset_t newset, oldset;

 

  sigfillset(&newset);

  sigprocmask(SIG_BLOCK, &newset, &oldset);

 

  pid_t pid = fork();

  if (pid == 0)

  child();

 

  printf("parent sleeping \n");

 

  int r = sleep(3);

 

  printf("woke up! r=%d\n", r);

 

  sigprocmask(SIG_SETMASK, &oldset, NULL);

 

  while (!done){

  };

 

  printf("exiting\n");

  exit(0);

}



编译源程序:

gcc test.c -o test



执行程序test,这时子程序发送了三次SIGRTMIN信号,父程序在过3秒后,接收并处理该信号.

./test

parent sleeping

child - BANG!

child - BANG!

child - BANG!

woke up! r=0

handled...

handled...

handled...

exiting



注意:这里有采用的是发送实时信号(SIGRTMIN),如:kill(getppid(), SIGRTMIN);

如果不是实时信号,则只能接收一次.



如果我们将pending signals值改为2,这里将只能保证挂起两个信号,第三个信号将被忽略.如下:

ulimit -i 2

./test

parent sleeping

child - BANG!

child - BANG!

child - BANG!

woke up! r=0

handled...

handled...

exiting





六)可以创建使用POSIX消息队列的最大值,单位为bytes.(POSIX message queues)



我们用下面的程序对POSIX消息队列的限制进行测试,如下:



#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#include <mqueue.h>

#include <sys/stat.h>

#include <sys/wait.h>



struct message{

 char mtext[128];

};



int send_msg(int qid, int pri, const char text[])

{

 int r = mq_send(qid, text, strlen(text) + 1,pri);

 if (r == -1){

  perror("mq_send");

 }

 return r;

}



void producer(mqd_t qid)

{

 send_msg(qid, 1, "This is my first message.");

 send_msg(qid, 1, "This is my second message.");



 send_msg(qid, 3, "No more messages.");

}



void consumer(mqd_t qid)

{

 struct mq_attr mattr;

 do{

  u_int pri;

  struct message msg;

  ssize_t len;



  len = mq_receive(qid, (char *)&msg, sizeof(msg), &pri);

  if (len == -1){

   perror("mq_receive");

   break;

  }

  printf("got pri %d '%s' len=%d\n", pri, msg.mtext, len);



  int r = mq_getattr(qid, &mattr);

  if (r == -1){

   perror("mq_getattr");

   break;

  }

 }while(mattr.mq_curmsgs);

}



int

main (int argc, char *argv[])

{

 struct mq_attr mattr = {

  .mq_maxmsg = 10,

  .mq_msgsize = sizeof(struct message)

 };



 mqd_t mqid = mq_open("/myq",

    O_CREAT|O_RDWR,

    S_IREAD|S_IWRITE,

    &mattr);

 if (mqid == (mqd_t) -1){

  perror("mq_open");

  exit (1);

 }



 pid_t pid = fork();

 if (pid == 0){

  producer(mqid);

  mq_close(mqid);

  exit(0);

 }

 else

 {

  int status;

  wait(&status);

  consumer(mqid);

  mq_close(mqid);

 }

 mq_unlink("/myq");

 return 0;

}





编译:

gcc test.c -o test



限制POSIX消息队列的最大值为1000个字节

ulimit -q 1000



这里我们执行test程序

./test

mq_open: Cannot allocate memory



程序报告无法分配内存.



用strace来跟踪test的运行过程,在下面一条语句时报错.

mq_open("myq", O_RDWR|O_CREAT, 0600, {mq_maxmsg=10, mq_msgsize=128}) = -1 ENOMEM (Cannot allocate memory)



{mq_maxmsg=10, mq_msgsize=128}即128*10=1280个字节,说明已经超过了1000个字节的POSIX消息队列限制.



我们将POSIX消息队列的最大值调整为1360时,程序可以运行.

ulimit -q 1360

./test

got pri 3 'No more messages.' len=18

got pri 1 'This is my first message.' len=26

got pri 1 'This is my second message.' len=27







七)程序占用CPU的时间,单位是秒(cpu time)



我们用下面的代码对程序占用CPU时间的限制进行测试



源程序如下:

# include <stdio.h>

# include <math.h>



int main (void)



{

  double pi=M_PI;

  double pisqrt;

  long i;



  while(1){

    pisqrt=sqrt(pi);

  }

  return 0;

}



编译:

gcc test.c -o test -lm



运行程序test,程序会一直循环下去,只有通过CTRL+C中断.

./test

^C



用ulimit将程序占用CPU的时间改为2秒,再运行程序.

ulimit -t 2

./test

Killed



程序最后被kill掉了.







八)限制程序实时优先级的范围,只针对普通用户.(real-time priority)



我们用下面的代码对程序实时优先级的范围进行测试



源程序如下:

# include <stdio.h>

int main (void)



{

  int i;

  for (i=0;i<6;i++)

  {

    printf ("%d\n",i);

    sleep(1);

  }

  return 0;

}



编译:

gcc test.c -o test



切换到普通用户进行测试

su - ckhitler



用实时优先级20运行test程序

chrt -f 20 ./test

chrt: failed to set pid 0's policy: Operation not permitted



我们用root将ulimit的实时优先级调整为20.再进行测试.

su - root

ulimit -r 20



切换到普通用户,用实时优先级20运行程序,可以运行这个程序了.

su - ckhitler

chrt -r 20 ./test

0

1

2

3

4

5



以实时优先级50运行程序,还是报错,说明ulimit的限制起了作用.

chrt -r 50 ./test

chrt: failed to set pid 0's policy: Operation not permitted





九)限制程序可以fork的进程数,只对普通用户有效(max user processes)



我们用下面的代码对程序的fork进程数的范围进行测试



源程序如下:

#include <unistd.h>

#include <stdio.h>

int main(void)

{

  pid_t pid;

  int count=0;

  while (count<3){

    pid=fork();

    count++;

    printf("count= %d\n",count);

  }

  return 0;

}



编译:

gcc test.c -o test

count= 1

count= 2

count= 3

count= 2

count= 3

count= 1

count= 3

count= 2

count= 3

count= 3

count= 3

count= 2

count= 3

count= 3



程序fork的进程数成倍的增加,这里是14个进程的输出.除自身外,其它13个进程都是test程序fork出来的.

我们将fork的限定到12,如下:

ulimit -u 12

再次执行test程序,这里只有12个进程的输出.

./test

count= 1

count= 2

count= 3

count= 1

count= 2

count= 3

count= 2

count= 3

count= 3

count= 2

count= 3

count= 3

count= 3



十)限制core文件的大小(core file size)



我们用下面的代码对程序生成core的大小进行测试



源代码:

#include <stdio.h>



static void sub(void);



int main(void)

{

     sub();

     return 0;

}



static void sub(void)

{

     int *p = NULL;

     printf("%d", *p);

}



编译:

gcc -g test.c -o test



运行程序test,出现段错误.

./test

Segmentation fault (core dumped)



如果在当前目录下没有core文件,我们应该调整ulimit对core的大小进行限制,如果core文件大小在这里指定为0,将不会产生core文件.

这里设定core文件大小为10个blocks.注:一个blocks在这里为1024个字节.



ulimit -c 10

再次运行这个程序

./test

Segmentation fault (core dumped)



查看core文件的大小

ls -lh core

-rw------- 1 root root 12K 2011-03-08 13:54 core



我们设定10个blocks应该是10*1024也不是10KB,为什么它是12KB呢,因为它的递增是4KB.

如果调整到14个blocks,我们将最大产生16KB的core文件.







十一)限制进程使用数据段的大小(data seg size)



一般来说这个限制会影响程序调用brk(系统调用)和sbrk(库函数)

调用malloc时,如果发现vm不够了就会用brk去内核申请.



限制可以使用最大为1KB的数据段



ulimit -d 1



用norff打开/etc/passwd文件

nroff /etc/passwd

Segmentation fault



可以用strace来跟踪程序的运行.

strace nroff /etc/passwd



打印出如下的结果,证明程序在分配内存时不够用时,调用brk申请新的内存,而由于ulimit的限制,导致申请失败.

munmap(0x7fc2abf00000, 104420)          = 0

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0

open("/dev/tty", O_RDWR|O_NONBLOCK)     = 3

close(3)                                = 0

brk(0)                                  = 0xf5b000

brk(0xf5c000)                           = 0xf5b000

brk(0xf5c000)                           = 0xf5b000

brk(0xf5c000)                           = 0xf5b000

--- SIGSEGV (Segmentation fault) @ 0 (0) ---

+++ killed by SIGSEGV +++

Segmentation fault





我们这里用一个测试程序对data segment的限制进行测试.

源程序如下:

#include <stdio.h>

int main()

{



    int start,end;

    start = sbrk(0);

    (char *)malloc(32*1024);

    end = sbrk(0);

    printf("hello I used %d vmemory\n",end - start);

    return 0;

}



gcc test.c -o test

 ./test

hello I used 0 vmemory



通过ulimit将限制改为170KB

再次运行程序

./test

hello I used 167936 vmemory







十二)限制进程使用堆栈段的大小



我们用ulimit将堆栈段的大小调整为16,即16*1024.

ulimit -s 16



再运行命令:

ls -l /etc/

Segmentation fault (core dumped)



这时用strace跟踪命令的运行过程

strace ls -l /etc/



发现它调用getrlimit,这里的限制是16*1024,不够程序运行时用到的堆栈.

getrlimit(RLIMIT_STACK, {rlim_cur=16*1024, rlim_max=16*1024}) = 0



注:在2.6.32系统上ls -l /etc/并不会出现堆栈不够用的情况,这时可以用expect来触发这个问题.



如:

expect

Tcl_Init failed: out of stack space (infinite loop?)





十三)限制进程使用虚拟内存的大小



我们用ulimit将虚拟内存调整为8192KB

ulimit -v 8192



运行ls

ls

ls: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory

ls在加载libc.so.6动态库的时候报了错,提示内存不足.





用strace跟踪ls的运行过程,看到下面的输出,说明在做mmap映射出内存时,出现内存不够用.

mmap(NULL, 3680296, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = -1 ENOMEM (Cannot allocate memory)

close(3)                                = 0

writev(2, [{"ls", 2}, {": ", 2}, {"error while loading shared libra"..., 36}, {": ", 2}, {"libc.so.6", 9}, {": ", 2}, {"failed to map segment from share"..., 40}, {": ", 2}, {"Cannot allocate memory", 22}, {"\n", 1}], 10ls: error while loading shared libraries:
libc.so.6: failed to map segment from shared object: Cannot allocate memory







十四)剩下的三种ulimit限制说明(file locks/max memory size/pipe size)




文件锁的限制只在2.4内核之前有用.

驻留内存的限制在很多系统里也没有作用.

管道的缓存不能改变,只能是8*512(bytes),也就是4096个字节.

作者:yuandianlws 发表于2013-8-26 12:37:01 原文链接
阅读:90 评论:0 查看评论

[转]linux的ulimit各种限制之深入分析的更多相关文章

  1. linux的ulimit各种限制之深入分析

    一般可以通过ulimit命令或编辑/etc/security/limits.conf重新加载的方式使之生效 通过ulimit比较直接,但只在当前的session有效,limits.conf中可以根据用 ...

  2. 正确设置Linux的ulimit值的方法

    学习swoole的时候有一个max_conn参数, max_conn 描述:服务器允许维持的最大TCP连接数 说明:设置此参数后,当服务器已有的连接数达到该值时,新的连接会被拒绝.另外,该参数的值不能 ...

  3. [转]正确配置Linux系统ulimit值的方法

    在Linux下面部署应用的时候,有时候会遇上Socket/File: Can't open so many files的问题:这个值也会影响服务器的最大并发数,其实Linux是有文件句柄限制的,而且L ...

  4. 正确配置Linux系统ulimit值的方法【转】

    转自:http://www.cnblogs.com/ibook360/archive/2012/05/11/2495405.html 在Linux下面部署应用的时候,有时候会遇上Socket/File ...

  5. linux 通过 ulimit 改善系统性能

    https://www.ibm.com/developerworks/cn/linux/l-cn-ulimit/ 概述 系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何 ...

  6. linux的ulimit命令

    ulimit命令用来限制系统用户对shell资源的访问. 语法: ulimit [-acdfHlmnpsStv] [size] 选项介绍:    -a 显示当前所有的资源限制;    -c size: ...

  7. linux设置ulimit值永久生效

    小知识的积累,转自 http://hi.baidu.com/moonelf9989/blog/item/1deadf12780fa0c5c2fd789d.html linux 默认打开文件数linux ...

  8. linux中ulimit作用

    一.作用 Linux对于每个用户,系统限制其最大进程数.为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数. ulimit主要是用来限制进程对资源的使用情况的,它支持各种类型的限制, ...

  9. Linux之ulimit详解(整理)

    修改:一般可以通过ulimit命令或编辑/etc/security/limits.conf重新加载的方式使之生效通过ulimit比较直接,但只在当前的session有效,limits.conf中可以根 ...

随机推荐

  1. jsp - java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver

    使用jsp连接数据库真的不那么容易,之前使用纯java连接sql Server 2008,都是很正常的,但是在使用jsp调用的时候,总是报错ClassNotFoundException.很郁闷 jar ...

  2. 读懂IL代码(三)

    由于要写毕业论文的缘故,最近比较没有时间写,总是要抽出时间抽出时间.诶,这样的生活比较烦躁. 这一篇主要写委托.类.方法的IL代码,一一来说明. 委托:搞过C#的都应该清楚,委托实际上是一个类.编译器 ...

  3. java动态绑定的情况分析

    java是面向对象的语言,java中多态的一种情况是动态绑定.所谓的动态绑定,分两种情况:当调用类方法的时候,java虚拟机会基于对象的引用类型来选择执行方法.当java调用一个实例方法的时候,他会根 ...

  4. phpmailer 发送邮件

    <?php /* 可用新浪和网易邮箱测试成功,但QQ不成功! 下载 phpmailer 解压 http://phpmailer.worxware.com/ 要注意邮件服务器的端口号,默认是 25 ...

  5. WPF自定义窗口(Windows Server 2012 Style)

    先上图 新建CustomControl,名:HeaderedWindow Themes\Generic.aml文件夹下加入 笔刷,转换器 <SolidColorBrush x:Key=" ...

  6. js设计模式--鸭子类型

    1.简介 JavaScript没有提供传统面向对象语言的类式继承通过原型委托的形式实现对象与对象之间的继承没有对抽象类和接口的支持 编程语言按数据类型可分为静态类型语言和动态类型语言 变量的类型要到程 ...

  7. transcode_step()在转码过程中对pts、dts、duration的处理

    对pts.dts.duration的处理主要集中在两大函数里面 1.process_input()读入数据并处理,放到滤镜里面 2.reap_filters()从滤镜读出数据,处理后写入文件 proc ...

  8. phpexcel的写出操作(生成excel表)

    /* thinkphp3.2 ThinkPHP/Library/Org/Util/ 放置位置 http://files.cnblogs.com/files/youligai/phpexcel.zip  ...

  9. JsRender

    JsRender 不少前端人员应该都用过,它是一个比较强大的模板,不牵涉太多技术依赖,使用起来非常舒服.我本人在前端开发中使用React之前,都是用的它了(实际上我感觉React没有JsViewes好 ...

  10. 解决delphi使用sqlite时中文最后一个字是乱码的问题

    给部门同事写了个自动生成测试用例执行情况图表的工具,使用的sqlite3,遇到中文分别使用UTF8Encode和UTF8Decode进行处理,可还是出现了某些字段从数据库中读出时,最后一个汉字是乱码的 ...