最大进程数量
LINUX中进程的最大理论数估算
每位进程的局部段描述表LDT都作为一个独立的段而存在,在全局段描述表GDT中要有一个表项指向这个段的起始地址,并说明该段的厚度以及其他一些参数。除上之外,每位进程还有一个TSS结构(任务状态段)也是一样。所以,每位进程都要在全局段描述表GDT中抢占两个表项。
段寄存器中用作GDT表下标的位段长度是13位,所以GDT中可以有213=8192213=8192个描述项。
除一些系统的开支(比如GDT中的第2项和第3项分别用于内核的代码段和数据段,第4项和第5项永远用于当前进程的代码段和数据段linux关机命令,第1项永远是0,等等)以外,尚有8180个表项可供使用,所以理论上系统中最大的进程数目是8180/2=40908180/2=4090。
所以系统中理论上最大的进程数是4090
系统中可创建的进程数实际值
linux内核通过进程标示值(processidentificationvalue)-PID来标识进程,PID是一个数,类型位pid_t,实际上就是int类型
为了与老版本的Unix或则Linux兼容,PID的最大值默认设置位32768(shortint短整型的最大值)。
可以使用cat/proc/sys/kernel/pid_max来查看系统中可创建的进程数实际值
ulimit -u 655351
设置完之后,尽管我们设置户创建进程数的硬限制和软限制都是65535,而且我们还不能使用创建65535个进程
我们在Linux还须要设置内核参数kernel.pid_max,这个参数我默认安装都是32768,
所以即便使用root账户,却不设置这个内核参数,整个系统最多可以创建的进程数就是32768,所以我们须要进行如下设置:
sysctl -w kernel.pid_max=655351
最大线程数
linux系统中单个进程的最大线程数有其最大的限制PTHREAD_THREADS_MAX
这个限制可以在/usr/include/bits/local_lim.h中查看
对linuxthreads这个值通常是1024,对于nptl则没有硬性的限制,仅仅受限于系统的资源
这个系统的资源主要就是线程的stack所占用的显存,用ulimit-s可以查看默认的线程栈大小,通常情况下,这个值是8M=8192KB
可以写一段简单的代码验证最多可以创建多少个线程
include
#include #include 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 = %dn", i);
} return EXIT_SUCCESS;
}
试验显示,在我们的系统(Ubuntu-14.04-LTS-64bit)中linuxthreads上最多可以创建381个线程,然后才会返回EAGAIN
LINUX中单个进程理论上可以创建的最大线程数
而32位系统中,可以穿件381个线程,这个值和理论完全相符,由于32位linux下的进程用户空间是3G的大小,也就是3072M,用3072M/8M=3843072M/8M=384,然而实际上代码段和数据段等还要占用一些空间,这个值应当向上取整到383,再除以主线程,得到382。
那为何linuxthreads上还要少一个线程呢?这可太对了,由于linuxthreads还须要一个管理线程
为了突破显存的限制,可以有两种方式
要注意的是,虽然这样的也未能突破1024个线程的硬限制,除非重新编译C库
最大打开文件数
file-max系统最大打开文件描述符数
/proc/sys/fs/file-max食指定了系统范围内所有进程可打开的文件句柄的数目限制(系统级别,kernel-level).
Thevalueinfile-maxdenotesthemaximumnumberoffilehandlesthattheLinuxkernelwillallocate).
当收到”Toomanyopenfilesinsystem”这样的错误消息时,就应当曾加这个值了.
对于2.2的内核,还须要考虑inode-max,通常inode-max设置为file-max的4倍.对于2.4及之后的内核,没有inode-max这个文件了.
查看实际值
可以使用cat/proc/sys/fs/file-max来查看当前系统上单进程可打开的文件描述符数量
186405
设置
echo1000000>/proc/sys/fs/file-maxfs.file-max=1000000
nr_open是单个进程可分配的最大文件数
内核支持的最大filehandle数目,即一个进程最多使用的filehandle数
themaximumnumberoffilesthatcanbeopenedbyprocess。
A process cannot use more than NR_OPEN file descriptors.
一个进程不能使用超过NR_OPEN文件描述符。12
须要C/C++Linux服务器构架师学习资料加qun获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,解释器,DPDK,ffmpeg等),免费分享
nofile进程最大打开文件描述符数
查看实际值
ulimit-n
其实默认查看的是软资源限制值softlimit,假如想要查看系统硬件所能支持的单进程最大打开文件描述符号的数量,可以使用ulimit-Hn
设置
通过ulimit-Sn设置最大打开文件描述符数的softlimit,注意softlimit不能小于hardlimit(ulimit-Hn可查看hardlimit)
另外ulimit-n默认查看的是softlimit,然而ulimit-n1800000则是同时设置softlimit和hardlimit。
对于非root用户只能设置比原先小的hardlimit。
里面的方式只是临时性的,注销重新登陆就失效了,但是不能减小hardlimit,只能在hardlimit范围内更改softlimit。
若要使更改永久有效,则须要在/etc/security/limits.conf中进行设置(须要root权限),可添加如下两行,表示用户chanon最大打开文件描述符数的softlimit为1800000,hardlimit为2000000。以下设置须要注销以后重新登陆能够生效:
chanon soft nofile 102400
chanon hard nofile 40960012
设置nofile的hardlimit还有一点要注意的就是hardlimit不能小于/proc/sys/fs/nr_openlinux线程栈大小,如果hardlimit小于nr_open,注销后未能正常登陆。
可以更改nr_open的值:
echo2000000>/proc/sys/fs/nr_open
file-max,nr_open,onfile之间的关系
针对用户打开最大文件数的限制,在limits.conf对应的nofile,不管是man指南还是文件中说明都只是一句话
“maximumnumberofopenfiles”linux重启命令,
它似乎对应是单个进程能打开的最大文件数,一般为了省事,我们想取消它的限制
按照man指南中,“values-1,unlimitedorinfinityindicatingnolimit”,-1、unlimited、infinity都是表明不做限制
但是当你实际给nofile设置成这个值,等你重启都会发觉未能登入系统了。
由此可见,nofile是有一个上限的,同时用ulimit测试:
ulimit -n unlimited1
bash:ulimit:openfiles:cannotmodifylimit:不容许的操作
写一个简单的for循环得出:
for V in `seq 100000 10000000`;do ulimit -n $V;[[ $? != 0 ]]&&break;done1
再执行ulimit-n,可以看见1048576就是nofile的最大值了,但为何是这个值?
1024∗1024=∗1024=1048576,其实这并没有哪些卵用。
再跟踪一下我们都会发觉这个值显然是由内核参数nr_open定义的:
cat /proc/sys/fs/nr_open 1
到此我们就要说起nr_open,与file-max了,网上在说到设置最大文件数时时常有些贴子也说到要更改file-max,字面上看file-max确实像是对应最大文件数,而在linux内核文档中它们两的解释是:
执行:grep-rMemTotal/proc/meminfo|awk‘{printf(“%d”,$2/10)}’,可以看见与file-max是相仿的;
file-handles(即文件句柄),之后相比而言在UNIX/LINUX中我们接触更多是filediscriptor(FD,即文件描述符),虽然file-handle在windows中是一个类似filediscrptor的东东,而且我们讨论的是linux,再google一下,我们可以精确到c语言中这两个概念的区别,
据她们的讨论file-handle应当是一个高层的对象,使用fopen,fread等函数来调用,而FD是底层的一个对象,可以通过open,read等函数来调用。
到此,我们应当可以下一个大致的推论了,file-max是内核可分配的最大文件数,nr_open是单个进程可分配的最大文件数,所以在我们使用ulimit或limits.conf来设置时,假如要超过默认的1048576值时须要先减小nr_open值(sysctl-wfs.nr_open=100000000或则直接写入sysctl.conf文件)。其实百万级别的单进程最大file-handle打开数应当也够用了吧。。
所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max单个进程打开的文件描述符数不能超过userlimit中nofile的softlimitnofile的softlimit不能超过其hardlimitnofile的hardlimit不能超过/proc/sys/fs/nr_open其他
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内核环境高linux线程栈大小,尤其要注意线程安全,否则即使是单CPU也会发生莫名其妙的显存不同步(CPU的高速缓存和寻址内容不一致),Intel的新CPU为了性能使用NUMA构架,在线程编程中一定要注意扬长避短。
单进程服务器最大并发线程数与显存
很有趣,在默认的ulimit参数下,不更改内核头文件
AS3512M显存最多1000并发持续联接
CentOS4.3512M显存最多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-s4096的情况下,单进程最大线程数在16000多一点,用top看
VIRT的上限是64G,也就是36位,cat/proc/cpuinfo的结果是:addresssizes:36bitsphysical,48bitsvirtual,和我想像的标准64位系统不同,我仍然以为64位系统的显存空间也是64位的
附注1
单位里某BSDFANS用AMD64电脑跑小程序测试线程创建速率(线程创建后立刻phread_detach()之后紧跟随pthread_exit(),共计100万个线程),同样源码OpenBSD居然比FreeBSD快了3倍,哪些时侯OpenBSD也显得疯狂上去了?
附注2
测试单进程创建线程上限C源码(test.c)
#include
#include
#include #include #include 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() failurernMax pthread num is %drn", i);
exit(-1);
} } fprintf(stdout, "Max pthread num is 65536rnYour system is power_fullrn");
exit(0);
}void * thread_null(void){ pthread_detach(pthread_self()); sleep(60);
pthread_exit(NULL);}