[关闭]
@Tmacy 2016-12-02T11:23:56.000000Z 字数 4315 阅读 1711

ulimit介绍与使用

linux 优化


概述

假设有这样一种情况,当一台 Linux 主机上同时登陆了 10 个人,在系统资源无限制的情况下,这 10 个用户同时打开了 500 个文档,而假设每个文档的大小有10M,这时系统的内存资源就会受到巨大的挑战。而实际应用的环境要比这种假设复杂的多,例如在一个嵌入式开发环境中,各方面的资源都是非常紧缺的,对于开启文件描述符的数量,分配堆栈的大小,CPU时间,虚拟内存大小等,都有非常严格的要求。

资源的合理限制和分配,不仅仅是保证系统可用性的必要条件,也与系统上软件运行的性能有着密不可分的联系。ulimit可以起到很大的作用,它是一种简单并且有效的实现资源限制的方式。

ulimit用于限制shell启动进程占用的资源,支持各种类型的限制:

  1. DeepinServer 15
  2. #ulimit -a
  3. core file size (blocks, -c) #core文件最大值
  4. data seg size (kbytes, -d) #数据段最大值
  5. scheduling priority (-e) #最大调度优先级
  6. file size (blocks, -f) #创建文件最大值
  7. pending signals (-i) #信号可以被挂起的最大数
  8. max locked memory (kbytes, -l) #最大可加锁的内存
  9. max memory size (kbytes, -m) #最大常驻内存
  10. open files (-n) #使用文件描述符上限
  11. pipe size (512 bytes, -p) #管道缓冲区最大数量
  12. POSIX message queues (bytes, -q) #POSIX信号队列最大值
  13. real-time priority (-r) #最大实时优先级
  14. stack size (kbytes, -s) #栈的最大值
  15. cpu time (seconds, -t) #cpu使用时间最大上限
  16. max user processes (-u) #用户线程最大值
  17. virtual memory (kbytes, -v) #虚拟内存上限
  18. file locks (-x) #文件锁上限

ulimit的使用

ulimit 命令的格式为:ulimit [options] [limit]

除了上列的几个资源限制参数,ulimit还有几个参数
-H : 设置硬资源,一旦设置不能再增加
例如:ulimit -Hs 64限制硬资源,线程栈大小为64k。
-S :设置软资源限制,设置后可以增加,但是不能超过硬资源
例如:ulimit -Sn 32限制软资源,32个文件描述符
-a 显示当前所有的limit 信息

我们可以通过一下几种方式来使用ulimit

1.在用户的启动脚本中
如果用户使用的是 bash,就可以在用户的目录下的 .bashrc 文件中,加入 ulimit – u 64,来限制用户最多可以使用 64 个进程。此外,可以在与 .bashrc 功能相当的启动脚本中加入 ulimt。
2.在应用程序的启动脚本中
如果用户要对某个应用程序 myapp 进行限制,可以写一个简单的脚本 startmyapp:

ulimit - s 512
myapp

3.直接在控制台输入
# ulimit -p 256
限制管道的缓冲区为256k

控制系统资源

ulimit作为对资源使用限制的一种工具,是有其所用范围的。它限制的对象是单个用户,还是单个进程,还是整个系统呢?
ulimit实际上限制的是当前shell进程以及其派生的子进程,对另一个shell终端包括其子进程都没有影响。

针对具体用户的资源加以限制的方法是修改系统的/etc/security/limits.conf文件。该文件不仅能限制用户的资源使用,还能制定组的资源使用情况。该文件的每一行都是对限定的描述,格式如下
<domain> <type> <item> <value>
domain 表示用户或者组的名字,还可以使用 * 作为通配符。Type 可以有两个值,soft 和 hard。
Item 则表示需要限定的资源,可以有很多候选值,如 stack,cpu,nofile 等等,分别表示最大的堆栈大小,占用的 cpu时间,以及打开的文件数。通过添加对应的一行描述,则可以产生相应的限制
* hard nofile 100表示任意用户所能创建的最大文件数是100

有时候,我们需要对整个系统的资源做总的限制,这时候我们需要修改/proc下的配置文件。/proc下包含了很多系统当前状态的配置文件。例如:/proc/sys/kernel/pid_max,/proc/sys/net/ipv4/ip_local_port_range 等等。大部分从文件名称就可以猜出限制资源的种类,我们可以根据需要针对修改。

ulimit 管理举例

1.限制 shell 的内存使用

  1. root@10-13-3-180:~# echo "test ulimit" > test
  2. root@10-13-3-180:~# ulimit -d 1000 -m 1000 -v 10000
  3. root@10-13-3-180:~# ls -l test
  4. ls: error while loading shared libraries: libpcre.so.3: failed to map segment from shared object: Cannot allocate memory
-m 设置常驻内存最大值
-d 设置数据段最大值
-v 设置虚拟内存最大值
上面的命令,我们已经把当前 shell 所能使用的最大内存限制在 1000KB        以下,导致ls命令运行失败。可以看到报错信息是无法分配内存,也就表示ulimit已经成功限制了系统资源。

2.限制创建文件大小

在没有限制的情况下,我们复制一个新的test文件:

  1. root@10-13-3-180:~# ls -l test
  2. -rw-r----- 1 root root 6711 Mar 15 15:03 test
  3. root@10-13-3-180:~# cat test > newTest
  4. root@10-13-3-180:~# ls -l newTest
  5. -rw-r--r-- 1 root root 6711 Mar 15 15:04 newTest

之后,我们设置ulimit -f 5,单位是blocks(1024 bytes)

  1. root@10-13-3-180:~# ulimit -f 5
  2. root@10-13-3-180:~# cat test > new
  3. File size limit exceeded (core dumped)

提示文件大小超出限制。我们查看new文件,大小为5120

  1. root@10-13-3-180:~# ls -l new
  2. -rw-r--r-- 1 root root 5120 Mar 15 15:06 new

关于block size的问题:

通常Linux的“block size”指的是1024 bytes,Linux用1024-byte blocks 作为buffer cache的基本单位。但linux的文件系统的block却不一样。例如ext3系统,block size是4096。使用tune2fs可以查看带文件系统的磁盘分区的相关信息,包括block size。
tune2fs -l /dev/sda1

1.硬件上的 block size, 应该是"sector size",linux的扇区大小是512byte

2.有文件系统的分区的block size, 是"block size",大小不一,可以用工具查看

3.没有文件系统的分区的block size,也叫“block size”,大小指的是1024 byte

4.Kernel buffer cache 的block size, 就是"block size",大部分PC是1024

3.限制socket数量

对于一个 C/S 模型中的 server 程序来说,它会为多个 client 程序请求创建多个 socket 端口给与响应。如果恰好有大量的 client 同时向 server 发出请求,那么此时 server 就会需要创建大量的 socket 连接。但在一个系统当中,往往需要限制单个 server程序所能使用的最大 socket 数,以供其他的 server 程序所使用。
我们发现,在ulimit的选项中没有限制socket的选项。但是socket是文件,我们可以利用限制文件描述符来起到限制socket的作用。

查看当前进程打开的文件描述符:

  1. root@10-13-3-180:~# ls /proc/3639/fd/ -l
  2. total 0
  3. lrwx------ 1 root root 64 Mar 15 14:59 0 -> /dev/null
  4. lrwx------ 1 root root 64 Mar 15 14:59 1 -> /dev/null
  5. lrwx------ 1 root root 64 Mar 15 15:36 10 -> /dev/ptmx
  6. lrwx------ 1 root root 64 Mar 15 14:59 2 -> /dev/null
  7. lrwx------ 1 root root 64 Mar 15 14:59 3 -> socket:[82797]
  8. lrwx------ 1 root root 64 Mar 15 14:59 4 -> socket:[83076]
  9. lr-x------ 1 root root 64 Mar 15 14:59 5 -> pipe:[83079]
  10. l-wx------ 1 root root 64 Mar 15 15:36 6 -> pipe:[83079]
  11. lrwx------ 1 root root 64 Mar 15 15:36 7 -> /dev/ptmx
  12. lrwx------ 1 root root 64 Mar 15 15:36 9 -> /dev/ptmx

4.限制堆栈数量

使用 -s(单位KB)来对线程的堆栈大小进行限制,从而减少整个多线程程序的内存使用,增加可用线程的数量。
我们所遇到的问题是系统对我们的多线程程序有如下的限制:
ulimit -v 200000
这意味着我们的程序最多只能使用不到 200MB 的虚拟内存。由于我们的程序是一个多线程程序,程序在运行时会根据需要创建新的线程,这势必会增加总的内存需求量。一开始我们对堆栈大小的限制是 1024 (本例子中使用 1232 来说明):
ulimit -s 1232
当我们的程序启动后,通过 pmap来查看其内存使用情况,可以看到多个占用 1232KB 的数据段,这些就是程序所创建的线程所使用的堆栈。
pic1
每当一个新的线程被创建时都需要新分配一段大小为 1232KB 的内存空间,而我们总的虚拟内存限制是 200MB,所以如果我们需要创建更多的线程,那么一个可以改进的方法就是减少每个线程的固定堆栈大小,这可以通过 ulimit – s 来实现:
ulimit -s 512
我们将堆栈大小设置为 512KB,这时再通过 pmap 查看一下我们的设置是否起作用:
pic2
从上面的信息可以看出,我们已经成功的将线程的堆栈大小改为 512KB 了,这样在总内存使用限制不变的情况下,我们可以通过本小节介绍的方法来增加可以创建的线程数,从而达到改善程序的多线程性能。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注