首页 > 代码库 > 通过ulimit改善系统性能
通过ulimit改善系统性能
本文介绍了ulimit 内键指令的主要功能以及用于改善系统性能的ulimit 使用方法。通过
这篇文章,读者不仅可以了解ulimit 所起的作用,并且可以学会如何更好地通过ulimit
限制资源的使用来改善系统性能。
概述
系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何
在有限资源的条件下保证程序的运作,ulimit 是我们在处理这些问题时,经常使用的一种
简单手段。ulimit 是一种linux 系统的内键功能,它具有一套参数集,用于为由它生成的
shell 进程及其子进程的资源使用设置限制。本文将在后面的章节中详细说明ulimit 的功
能,使用以及它的影响,并以具体的例子来详细地阐述它在限制资源使用方面的影响。
ulimit 的功能和用法
ulimit 功能简述
假设有这样一种情况,当一台Linux 主机上同时登陆了10 个人,在系统资源无限制的情
况下,这10 个用户同时打开了500 个文档,而假设每个文档的大小有10M,这时系统
的内存资源就会受到巨大的挑战。
而实际应用的环境要比这种假设复杂的多,例如在一个嵌入式开发环境中,各方面的资源都
是非常紧缺的,对于开启文件描述符的数量,分配堆栈的大小,CPU 时间,虚拟内存大小,
等等,都有非常严格的要求。资源的合理限制和分配,不仅仅是保证系统可用性的必要条件,
也与系统上软件运行的性能有着密不可分的联系。这时,ulimit 可以起到很大的作用,它
是一种简单并且有效的实现资源限制的方式。
ulimit 用于限制shell 启动进程所占用的资源,支持以下各种类型的限制:所创建的内核
文件的大小、进程数据块的大小、Shell 进程创建文件的大小、内存锁住的大小、常驻内存
集的大小、打开文件描述符的数量、分配堆栈的最大大小、CPU 时间、单个用户的最大线
程数、Shell 进程所能使用的最大虚拟内存。同时,它支持硬资源和软资源的限制。
作为临时限制,ulimit 可以作用于通过使用其命令登录的shell 会话,在会话终止时便结
束限制,并不影响于其他shell 会话。而对于长期的固定限制,ulimit 命令语句又可以被
回页首
添加到由登录shell 读取的文件中,作用于特定的shell 用户。
图 1. ulimit 的使用
在下面的章节中,将详细介绍如何使用ulimit 做相应的资源限制。
如何使用 ulimit
ulimit 通过一些参数选项来管理不同种类的系统资源。在本节,我们将讲解这些参数的使
用。
ulimit 命令的格式为:ulimit [options] [limit]
具体的options 含义以及简单示例可以参考以下表格。
表 1. ulimit 参数说明
选项
[option
s]
含义例子
-H 设置硬资源限制,一旦设置不能增加。ulimit -Hs 64;限制硬资源,线程栈大小为64K。
-S 设置软资源限制,设置后可以增加,但是不能超过硬资源设置。ulimit – Sn 32;限制软资源,32 个文件描述符。
-a 显示当前所有的limit 信息。ulimit -a;显示当前所有的limit 信息。
-c 最大的core 文件的大小, 以blocks为单位。ulimit -c unlimited; 对生成的core 文件的大小不进行限制。
-d 进程最大的数据段的大小,以Kbytes为单位。ulimit -d unlimited;对进程的数据段大小不进行限制。
-f 进程可以创建文件的最大值,以blocks为单位。ulimit -f 2048;限制进程可以创建的最大文件大小为2048 blocks。
-l 最大可加锁内存大小,以Kbytes 为单位。ulimit -l 32;限制最大可加锁内存大小为32 Kbytes。
-m 最大内存大小,以Kbytes 为单位。ulimit -m unlimited;对最大内存不进行限制。
我们可以通过以下几种方式来使用ulimit:
在用户的启动脚本中
如果用户使用的是bash,就可以在用户的目录下的.bashrc 文件中,加入ulimit – u
64,来限制用户最多可以使用64 个进程。此外,可以在与.bashrc 功能相当的启动脚
本中加入ulimt。
在应用程序的启动脚本中
如果用户要对某个应用程序myapp 进行限制,可以写一个简单的脚本startmyapp。
以后只要通过脚本startmyapp 来启动应用程序,就可以限制应用程序myapp 的线程
栈大小为512K。
直接在控制台输入
限制管道的缓冲区为256K。
-n 可以打开最大文件描述符的数量。ulimit - n 128;限制最大可以使用128文件描述符。
-p 管道缓冲区的大小,以Kbytes 为单位。ulimit - p 512;限制管道缓冲区的大小为512 Kbytes。
-s 线程栈大小,以Kbytes 为单位。ulimit -s 512;限制线程栈的大小为512Kbytes。
-t 最大的CPU 占用时间,以秒为单位。ulimit -t unlimited;对最大的CPU 占用时间不进行限制。
-u 用户最大可用的进程数。ulimit -u 64;限制用户最多可以使用64个进程。
-v 进程最大可用的虚拟内存,以Kbytesulimit -v 200000;限制最大可用的虚拟内存为200000 Kbytes。
ulimit – s 512
myapp
user@tc511-ui:~>ulimit – p 256
用户进程的有效范围
ulimit 作为对资源使用限制的一种工作,是有其作用范围的。那么,它限制的对象是单个
用户,单个进程,还是整个系统呢?事实上,ulimit 限制的是当前shell 进程以及其派生
的子进程。举例来说,如果用户同时运行了两个shell 终端进程,只在其中一个环境中执
行了ulimit – s 100,则该shell 进程里创建文件的大小收到相应的限制,而同时另一个
shell 终端包括其上运行的子程序都不会受其影响:
Shell 进程 1
Shell 进程 2
那么,是否有针对某个具体用户的资源加以限制的方法呢?答案是有的,方法是通过修改系
回页首
ulimit – s 100
cat testFile > newFile
File size limit exceeded
cat testFile > newFile
ls – s newFile
323669 newFile
统的/etc/security/limits 配置文件。该文件不仅能限制指定用户的资源使用,还能限制
指定组的资源使用。该文件的每一行都是对限定的一个描述,格式如下:
domain 表示用户或者组的名字,还可以使用* 作为通配符。Type 可以有两个值,soft 和
hard。Item 则表示需要限定的资源,可以有很多候选值,如stack,cpu,nofile 等等,
分别表示最大的堆栈大小,占用的cpu 时间,以及打开的文件数。通过添加对应的一行描
述,则可以产生相应的限制。例如:
该行配置语句限定了任意用户所能创建的最大文件数是100。
现在已经可以对进程和用户分别做资源限制了,看似已经足够了,其实不然。很多应用需要
对整个系统的资源使用做一个总的限制,这时候我们需要修改/proc 下的配置文件。/proc
目录下包含了很多系统当前状态的参数, 例如/proc/sys/kernel/pid_max ,
/proc/sys/net/ipv4/ip_local_port_range 等等,从文件的名字大致可以猜出所限制的
资源种类。由于该目录下涉及的文件众多,在此不一一介绍。有兴趣的读者可打开其中的相
关文件查阅说明。
* hard noflle 100
回页首
ulimit 管理系统资源的例子
ulimit 提供了在shell 进程中限制系统资源的功能。本章列举了一些使用ulimit 对用户
进程进行限制的例子,详述了这些限制行为以及对应的影响,以此来说明ulimit 如何对系
统资源进行限制,从而达到调节系统性能的功能。
使用 ulimit 限制 shell 的内存使用
在这一小节里向读者展示如何使用– d,– m 和– v 选项来对shell 所使用的内存进行限
制。
首先我们来看一下不设置ulimit 限制时调用ls 命令的情况:
图 2. 未设置 ulimit 时 ls 命令使用情况
大家可以看到此时的ls 命令运行正常。下面设置ulimit:
这里再温习一下前面章节里介绍过的这三个选项的含义:
-d:设置数据段的最大值。单位:KB。
-m:设置可以使用的常驻内存的最大值。单位:KB。
-v:设置虚拟内存的最大值。单位:KB。
通过上面的ulimit 设置我们已经把当前shell 所能使用的最大内存限制在1000KB 以
下。接下来我们看看这时运行ls 命令会得到什么样的结果:
从上面的结果可以看到,此时ls 运行失败。根据系统给出的错误信息我们可以看出是由于
调用libc 库时内存分配失败而导致的ls 出错。那么我们来看一下这个libc 库文件到底
>ulimit -d 1000 -m 1000 -v 1000
Master:~ # ls test -lh
Segmentation fault 提示分段错误
解决方法
>ulimit -d unlimited;对进程的数据段大小不进行限制
>ulimit -m unlimited;对最大内存不进行限制
>ulimit -v 2000000 ;限制最大可用的虚拟内存为2000000 Kbytes。
有多大:
图 3. 查看 libc 文件大小
从上面的信息可以看出,这个libc 库文件的大小是1.5MB。而我们用ulimit 所设置的
内存使用上限是1000KB,小于1.5MB,这也就充分证明了ulimit 所起到的限制shell
内存使用的功能。
使用 ulimit 限制 shell 创建的文件的大小
接下来向读者展示如何使用-f 选项来对shell 所能创建的文件大小进行限制。
首先我们来看一下,没有设置ulimit -f 时的情况:
图 4. 查看文件
现有一个文件testFile 大小为323669 bytes,现在使用cat 命令来创建一个testFile
的copy:
图 5. 未设置 ulimit 时创建复本
从上面的输出可以看出,我们成功的创建了testFile 的拷贝newFile。
下面我们设置ulimt – f 100:
> ulimit -f 100
-f 选项的含义是:用来设置shell 可以创建的文件的最大值。单位是blocks。
现在我们再来执行一次相同的拷贝命令看看会是什么结果:
图 6. 设置 ulimit 时创建复本
这次创建testFile 的拷贝失败了,系统给出的出错信息时文件大小超出了限制。在Linux
系统下一个block 的默认大小是512 bytes。所以上面的ulimit 的含义就是限制shell
所能创建的文件最大值为512 x 100 = 51200 bytes,小于323669 bytes,所以创建
文件失败,符合我们的期望。这个例子说明了如何使用ulimit 来控制shell 所能创建的
最大文件。
使用 ulimit 限制程序所能创建的 socket 数量
考虑一个现实中的实际需求。对于一个C/S 模型中的server 程序来说,它会为多个
client 程序请求创建多个socket 端口给与响应。如果恰好有大量的client 同时向
server 发出请求,那么此时server 就会需要创建大量的socket 连接。但在一个系统当
中,往往需要限制单个server 程序所能使用的最大socket 数,以供其他的server 程
序所使用。那么我们如何来做到这一点呢?答案是我们可以通过ulimit 来实现!细心的读
者可能会发现,通过前面章节的介绍似乎没有限制socket 使用的ulimit 选项。是的,
ulimit 并没有哪个选项直接说是用来限制socket 的数量的。但是,我们有-n 这个选项,
它是用于限制一个进程所能打开的文件描述符的最大值。在Linux 下一切资源皆文件,普
通文件是文件,磁盘打印机是文件,socket 当然也是文件。在Linux 下创建一个新的
socket 连接,实际上就是创建一个新的文件描述符。如下图所示(查看某个进程当前打开
的文件描述符信息):
图 7. 查看进程打开文件描述符
因此,我们可以通过使用ulimit – n 来限制程序所能打开的最大文件描述符数量,从而达
到限制socket 创建的数量。
使用 ulimit 限制 shell 多线程程序堆栈的大小(增加可用线程数量)
在最后一个例子中,向大家介绍如何使用-s(单位KB)来对线程的堆栈大小进行限制,
从而减少整个多线程程序的内存使用,增加可用线程的数量。这个例子取自于一个真实的案
例。我们所遇到的问题是系统对我们的多线程程序有如下的限制:
ulimit -v 200000
根据本文前面的介绍,这意味着我们的程序最多只能使用不到200MB 的虚拟内存。由于
我们的程序是一个多线程程序,程序在运行时会根据需要创建新的线程,这势必会增加总的
内存需求量。一开始我们对堆栈大小的限制是1024 (本例子中使用1232 来说明):
当我们的程序启动后,通过pmap 来查看其内存使用情况,可以看到多个占用1232KB
的数据段,这些就是程序所创建的线程所使用的堆栈:
图 8. 程序线程所使用的堆栈
每当一个新的线程被创建时都需要新分配一段大小为1232KB 的内存空间,而我们总的虚
拟内存限制是200MB,所以如果我们需要创建更多的线程,那么一个可以改进的方法就是
减少每个线程的固定堆栈大小,这可以通过ulimit – s 来实现:
我们将堆栈大小设置为512KB,这时再通过pmap 查看一下我们的设置是否起作用:
# ulimit – s 1232
# ulimit -s 512
图 9. 设置 ulimit 后堆栈大小
从上面的信息可以看出,我们已经成功的将线程的堆栈大小改为512KB 了,这样在总内
存使用限制不变的情况下,我们可以通过本小节介绍的方法来增加可以创建的线程数,从而
达到改善程序的多线程性能。
总结
综上所述,linux 系统中的ulimit 指令,对资源限制和系统性能优化提供了一条便捷的途
径。从用户的shell 启动脚本,应用程序启动脚本,以及直接在控制台,都可以通过该指
令限制系统资源的使用,包括所创建的内核文件的大小、进程数据块的大小、Shell 进程创
建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的
最大大小、CPU 时间、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存,等
等方面。本文中的示例非常直观的说明了ulimit 的使用及其产生的效果,显而易见,ulimit
对我们在Linux 平台的应用和开发工作是非常实用的。
本文出自 “吕布天下” 博客,请务必保留此出处http://2364821.blog.51cto.com/2354821/1408203