ulimit指令檢視和更改系統限制
ulimit指令詳解
ulimit用于shell啟動程序所占用的資源,可以用來設定系統的限制
文法格式
ulimit [-acdfHlmnpsStvw] [size]
在
/etc/security/limits.conf
檔案中定義
限制。
指令參數 | 描述 | 例子 |
-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;對最大記憶體不進行限制 |
-n | 可以打開最大檔案描述符的數量 | ulimit – n 128;限制最大可以使用 128 個檔案描述符 |
-p | 管道緩沖區的大小,以 Kbytes 為機關 | ulimit – p 512;限制管道緩沖區的大小為 512 Kbytes |
-s | 線程棧大小,以 Kbytes 為機關 | ulimit – s 512;限制線程棧的大小為 512 Kbytes |
-t | 最大的 CPU 占用時間,以秒為機關 | ulimit – t unlimited;對最大的 CPU 占用時間不進行限制 |
-u | 使用者最大可用的程序數 | ulimit – u 64;限制使用者最多可以使用 64 個程序 |
-v | 程序最大可用的虛拟記憶體,以 Kbytes 為機關 | ulimit – v 200000;限制最大可用的虛拟記憶體為 200000 Kbytes |
我們可以使用ulimit -a檢視我們系統的所有限制
當然我們都知道linux大部分的指令設定都是臨時生效,而且ulimit指令隻對目前終端生效
如果需要永久生效的話,我們有兩種方法,
- 一種是将指令寫至profile和bashrc中,相當于在登陸時自動動态修改限制
- 還有一種就是在/etc/security/limits.conf中添加記錄(需重新開機生效,并且在/etc/pam.d/中的seesion有使用到limit子產品)。
limits.conf檔案附錄
在/etc/security/limits.conf修改限制的格式如下
domino type item value
參數 | |
domino | 是以符号@開頭的使用者名或組名,*表示所有使用者 |
type | 設定為hard or soft |
item | 指定想限制的資源。如cpu,core nproc or maxlogins |
value | 是相應的 |
最大程序數目
LINUX中程序的最大理論數計算
- 每個程序都要在全局段描述表GDT中占據兩個表項
每個程序的局部段描述表LDT都作為一個獨立的段而存在,在全局段描述表GDT中要有一個表項指向這個段的起始位址,并說明該段的長度以及其他一些 參數。除上之外,每個程序還有一個TSS結構(任務狀态段)也是一樣。是以,每個程序都要在全局段描述表GDT中占據兩個表項。
- GDT的容量有多大呢?
段寄存器中用作GDT表下标的位段寬度是13位,是以GDT中可以有213=8192個描述項。
除一些系統的開銷(例如GDT中的第2項和第3項分别用于核心 的代碼段和資料段,第4項和第5項永遠用于目前程序的代碼段和資料段,第1項永遠是0,等等)以外,尚有8180個表項可供使用,是以理論上系統中最大的 程序數量是8180/2=4090。
是以系統中理論上最大的程序數是4090
系統中可建立的程序數實際值
linux核心通過程序辨別值(process identification value)-PID來标示程序,PID是一個數,類型位pid_t, 實際上就是int類型
為了與老版本的Unix或者Linux相容,PID的最大值預設設定位32768(short int 短整型的最大值)。
- 檢視
可以使用
cat /proc/sys/kernel/pid_max
來檢視系統中可建立的程序數實際值
- 修改
ulimit -u 65535
設定完以後,雖然我們設定戶建立程序數的硬限制和軟限制都是65535,但是我們還不能使用建立65535個程序
我們在Linux還需要設定核心參數kernel.pid_max,這個參數我預設安裝都是32768,
是以即使使用root帳戶,卻不設定這個核心參數,整個系統最多可以建立的程序數就是32768,是以我們需要進行如下設定:
sysctl -w kernel.pid_max=65535
最大線程數
linux 系統中單個程序的最大線程數有其最大的限制
PTHREAD_THREADS_MAX
這個限制可以在
/usr/include/bits/local_lim.h
中檢視
對 linuxthreads 這個值一般是 1024,對于 nptl 則沒有硬性的限制,僅僅受限于系統的資源
這個系統的資源主要就是線程的 stack 所占用的記憶體,用 ulimit -s 可以檢視預設的線程棧大小,一般情況下,這個值是
8M=8192KB
可以寫一段簡單的代碼驗證最多可以建立多少個線程
include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void func()
{
}
int main(void)
{
int i = 0;
pthread_t thread;
while ( 1 )
{
if (pthread_create(&thread, NULL, func, NULL) != 0)
{
return;
}
i++;
printf("i = %d\n", i);
}
return EXIT_SUCCESS;
}
試驗顯示,在我們的系統(Ubuntu-14.04-LTS-64bit)中linuxthreads 上最多可以建立 381 個線程,之後就會傳回 EAGAIN
LINUX中單個程序理論上可以建立的最大線程數
而32位系統中,可以穿件381個線程,這個值和理論完全相符,因為 32 位 linux 下的程序使用者空間是 3G 的大小,也就是 3072M,用3072M/8M=384,但是實際上代碼段和資料段等還要占用一些空間,這個值應該向下取整到 383,再減去主線程,得到 382。
那為什麼 linuxthreads 上還要少一個線程呢?這可太對了,因為 linuxthreads 還需要一個管理線程
為了突破記憶體的限制,可以有兩種方法
- 用
減小預設的棧大小ulimit -s 1024
- 調用
的時候用pthread_create
設定一個較小的棧大小pthread_attr_getstacksize
要注意的是,即使這樣的也無法突破1024 個線程的硬限制,除非重新編譯 C 庫
最大打開檔案數
file-max系統最大打開檔案描述符數
/proc/sys/fs/file-max中指定了系統範圍内所有程序可打開的檔案句柄的數量限制(系統級别, kernel-level).
The value in file-max denotes the maximum number of file handles that the Linux kernel will allocate).
當收到”Too many open files in system”這樣的錯誤消息時, 就應該曾加這個值了.
對于2.2的核心, 還需要考慮inode-max, 一般inode-max設定為file-max的4倍. 對于2.4及以後的核心, 沒有inode-max這個檔案了.
檢視實際值
可以使用cat /proc/sys/fs/file-max來檢視目前系統中單程序可打開的檔案描述符數目
186405
設定
- 臨時性
echo 1000000 > /proc/sys/fs/file-max
- 永久性:在/etc/sysctl.conf中設定
fs.file-max = 1000000
nr_open是單個程序可配置設定的最大檔案數
核心支援的最大file handle數量,即一個程序最多使用的file handle數
the maximum number of files that can be opened by process。
A process cannot use more than NR_OPEN file descriptors.
一個程序不能使用超過NR_OPEN檔案描述符。
nofile程序最大打開檔案描述符數
ulimit -n
當然預設檢視的是軟資源限制值soft limit,如果想要檢視系統硬體所能支援的單程序最大打開檔案描述符号的數目,可以使用ulimit -Hn
通過
ulimit -Sn
設定最大打開檔案描述符數的soft limit,注意soft limit不能大于hard limit(ulimit -Hn可檢視hard limit)
另外ulimit -n預設檢視的是soft limit,但是ulimit -n 1800000則是同時設定soft limit和hard limit。
對于非root使用者隻能設定比原來小的hard limit。
- 永久性
上面的方法隻是臨時性的,登出重新登入就失效了,而且不能增大hard limit,隻能在hard limit範圍内修改soft limit。
若要使修改永久有效,則需要在/etc/security/limits.conf中進行設定(需要root權限),可添加如下兩行,表示使用者chanon最大打開檔案描述符數的soft limit為1800000,hard limit為2000000。以下設定需要登出之後重新登入才能生效:
chanon soft nofile 102400
chanon hard nofile 409600
設定nofile的hard limit還有一點要注意的就是hard limit不能大于/proc/sys/fs/nr_open,假如hard limit大于nr_open,登出後無法正常登入。
可以修改nr_open的值:
echo 2000000 > /proc/sys/fs/nr_open
file-max, nr_open, onfile之間的關系
針對使用者打開最大檔案數的限制, 在limits.conf對應的nofile,不管是man手冊還是檔案中說明都隻是一句話
“maximum number of open files”,
它其實對應是單個程序能打開的最大檔案數,通常為了省事,我們想取消它的限制
根據man手冊中,“values -1, unlimited or infinity indicating no limit”,-1、unlimited、infinity都是表明不做限制
可是當你實際給nofile設定成這個值,等你重新開機就會發現無法登入系統了。
由此可見,nofile是有一個上限的,同時用ulimit測試:
ulimit -n unlimited
bash: ulimit: open files: cannot modify limit: 不允許的操作
寫一個簡單的for循環得出:
for V in `seq 100000 10000000`;do ulimit -n $V;[[ $? != 0 ]]&&break;done
再執行ulimit -n ,可以看到1048576就是nofile的最大值了,但為什麼是這個值?
1024∗1024=1048576,當然這并沒有什麼卵用。
再跟蹤一下我們就會發現這個值其實是由核心參數nr_open定義的:
cat /proc/sys/fs/nr_open
到此我們就要說起nr_open,與file-max了,網上在說到設定最大檔案數時偶爾有些文章也說到要修改file-max,字面上看file-max确實像是對應最大檔案數,而在linux核心文檔中它們兩的解釋是:
-
file-max:
The value in file-max denotes the maximum number of file-
handles that the Linux kernel will allocate. When you get lots
of error messages about running out of file handles, you might
want to increase this limit
執行:grep -r MemTotal /proc/meminfo | awk ‘{printf(“%d”,$2/10)}’,可以看到與file-max是相近的;
-
nr_open:
This denotes the maximum number of file-handles a process can
allocate. Default value is 1024*1024 (1048576) which should be
enough for most machines. Actual limit depends on RLIMIT_NOFILE
resource limit.
file-handles(即檔案句柄),然後相比而言在UNIX/LINUX中我們接觸更多是file discriptor(FD,即檔案描述符),似乎file-handle在windows中是一個類似file discrptor的東東,但是我們讨論的是linux,再google一下,我們可以精确到c語言中這兩個概念的差別,
據他們的讨論file-handle應該是一個高層的對象,使用fopen,fread等函數來調用,而FD是底層的一個對象,可以通過open,read等函數來調用。
到此,我們應該可以下一個大緻的結論了,file-max是核心可配置設定的最大檔案數,nr_open是單個程序可配置設定的最大檔案數,是以在我們使用ulimit或limits.conf來設定時,如果要超過預設的1048576值時需要先增大nr_open值(sysctl -w fs.nr_open=100000000或者直接寫入sysctl.conf檔案)。當然百萬級别的單程序最大file-handle打開數應該也夠用了吧。。
- 所有程序打開的檔案描述符數不能超過/proc/sys/fs/file-max
- 單個程序打開的檔案描述符數不能超過user limit中nofile的soft limit
- nofile的soft limit不能超過其hard limit
- nofile的hard limit不能超過/proc/sys/fs/nr_open
其他
如下内容轉載自
linux 單程序可建立最大線程數
2.4核心與2.6核心的主要差別
在2.4核心的典型系統上(AS3/RH9),線程是用輕量程序實作的,每個線程要占用一個程序ID,在伺服器程式上,如果遇到高點選率通路,會造成程序表溢出,系統為了維護溢出的程序表,會有間歇的暫停服務現象,而2.6核心就不會發生由于大量線程的建立和銷毀導緻程序表溢出的問題
線程結束必須釋放線程堆棧
就是說,線程函數必須調用pthread_exit()結束,否則直到主程序函數退出才釋放,特别是2.6核心環境,線程建立速度飛快,一不小心立刻記憶體被吃光,這一點反倒是2.4核心環境好,因為2.4核心建立的是程序,而且線程建立速度比2.6核心慢幾個數量級。特别提醒,在64位CPU,2.6核心建立線程的速度更加瘋狂,要是太快的話,加上usleep ()暫停一點點時間比較好
不要編需要鎖的線程應用
隻有那些不需要互斥量的程式才能最大限度的利用線程程式設計帶來的好處,否則隻會更慢,2.6核心是搶占式核心,線程間共享沖突發生的幾率遠比2.4核心環境高,尤其要注意線程安全,否則就算是單CPU也會發生莫名其妙的記憶體不同步(CPU的高速緩存和主存内容不一緻),Intel的新CPU為了性能使用NUMA架構,線上程程式設計中一定要注意揚長避短。
單程序伺服器最大并發線程數與記憶體
很有趣,在預設的ulimit參數下,不修改核心頭檔案
AS3 512M記憶體最多1000并發持續連接配接
CentOS4.3 512M記憶體最多300并發持續連接配接
似乎是CentOS不如AS3,這裡主要原因是ulimit的配置造成,兩個系統預設的配置差距很大,要想單程序維持更多線程接收并發連接配接,就要盡量縮小 ulimit -s的參數,插更多的記憶體條,單程序伺服器上2000并發一點都不難,POSIX預設的限制是每程序64線程,但NTPL并非純正POSIX,不必理會這個限制,2.6核心下真正的限制是記憶體條的插槽數目(也許還有買記憶體的錢數)
最近幾天的程式設計中,注意到在32位x86平台上2.6核心單程序建立最大線程數=VIRT上限/stack,與總記憶體數關系不大,32位x86系統預設的VIRT上限是3G(記憶體配置設定的3G+1G方式),預設 stack大小是10240K,是以單程序建立線程預設上限也就300(3072M / 10240K),用ulimit -s 修改stack到1024K則使上限升到大約3050。我手頭沒有64位系統,不知道2.6核心在64位上單程序建立線程上限(實際上是本人懶得在同僚的機器上裝fc4_x86_64)。
前些天買了一套廉價的64位x86系統(64位賽楊+雜牌915主機闆),安裝了CentOS4.3的x86_64版本,跑了一遍下面的小程式,得到的結果是:在ulimit -s 4096的情況下,單程序最大線程數在16000多一點,用top看
VIRT 的上限是64G,也就是36位, cat /proc/cpuinfo的結果是:address sizes : 36 bits physical, 48 bits virtual, 和我想象的标準64位系統不同, 我一直以為64位系統的記憶體空間也是64位的
附注1
機關裡某BSD FANS用AMD64筆記本跑小程式測試線程建立速度(線程建立後立即phread_detach()然後緊跟着pthread_exit(),共計 100萬個線程),同樣源碼OpenBSD竟然比FreeBSD快了3倍,什麼時候OpenBSD也變得瘋狂起來了?
附注2
測試單程序建立線程上限C源碼(test.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void * thread_null(void);
int main(int argc, char *argv[])
{
unsigned int i;
int rc;
pthread_t pool_id[65536]; //線程ID
sleep(1);
//建立線程
for(i = 0; i < 65536; i++)
{
rc = pthread_create(pool_id + i, 0, (void *)thread_null, NULL);
if (rc != 0)
{
fprintf(stderr, "pthread_create() failure\r\nMax pthread num is %d\r\n", i);
exit(-1);
}
}
fprintf(stdout, "Max pthread num is 65536\r\nYour system is power_full\r\n");
exit(0);
}
void * thread_null(void)
{
pthread_detach(pthread_self());
sleep(60);
pthread_exit(NULL);
}
技術連結