通過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 平臺的應用和開發工作是非常實用的。  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章