一直做Windows服务器向Linux平台的移植工作,对于线程的栈空间也是似懂非懂,因而出现了一些问题和总结了部分经验,供大家分享。
在我的服务器上启动了286个线程后,其后的线程启动失败了,返回的错误原因是12,经查找定义如下:
#define
ENOMEM
12
/* Out of memory */
看来创建线程失败的原因是分配内存失败,同时进程占用的VIRT显示也达到了3070MB,估计是虚拟内存不足了。
于是查看了两个平台关于线程堆栈空间方面的内容,列举如下:
在Windows中,CreateThread函数的参数dwStackSize是将要分配给新线程的以字节为单位的栈大小。栈大小应该是4KB的非零整数倍,最小为8KB。堆栈默认的大小1MB。
在Linux中,线程堆栈大小遵照系统的默认设置或在线程属性对象中设置,而我没有进行设置,于是使用ulimit命令查看了系统的堆栈大小,如下:
stack size
(kbytes, -s) 10240
怪不得使用了如此多的虚拟内存呢,286*10M=2860M,再加上其他部分消耗的,所以虚拟内存就不足了。
另外查阅文档,反映Linux平台的栈默认大小应该是8192KB,而不是10M;但我这台服务器是否被别人修改了就不清楚了。
Linux平台使用如下函数操作POSIX线程栈空间:
int pthread_attr_setstacksize(pthread_attr_t *threadAttr, int stack_size);//设置
int pthread_attr_getstacksize(pthread_attr_t *threadAttr, int stack_size);//取得
马上使用上述函数进行了测试,流程如下:
在 Linux 中,栈大小在线程属性对象中设置,也就是说,将类型为“pthread_attr_t”的参数“threadAttr”传递给函数 pthread_create()。在设置属性之前,需要通过调用 pthread_attr_init() 来初始化这个对象,然后使用pthread_attr_setstacksize()函数设置线程栈空间大小,单位为字节;接着调用pthread_create()创建线程,完毕后调用 pthread_attr_destroy()来销毁属性对象。
把线程栈空间设置为2M后进行了测试,确认成功减小了创建线程消耗的虚拟内存了。
注意,所有 pthread_attr_setxxxx 调用都有与 pthread_xxxx 调用(如果有)类似的功能,只是您只能在线程创建之前使用 pthread_attr_xxxx,来更新将要作为参数传递给 pthread_create 的属性对象。同时,您在创建线程之后的任意时候都可以使用 pthread_xxxx进行修改。