线程栈空间的大小

本文介绍了作者在从Windows服务器向Linux平台移植过程中遇到的线程创建失败问题,并详细解释了如何调整Linux平台上的线程栈空间大小以解决内存不足的问题。
一直做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进行修改。

### Linux 实时获取线程栈空间大小的方法 在 Linux 系统中,实时获取线程栈空间大小可以通过多种方法实现。以下将详细介绍几种常见的方式,并结合提供的引用内容进行说明。 #### 1. 使用 `/proc` 文件系统 Linux 提供了 `/proc` 文件系统,其中每个进程都有一个对应的目录,路径为 `/proc/<pid>/task/<tid>/maps`,这里 `<pid>` 是进程 ID,而 `<tid>` 是线程 ID。通过解析该文件,可以找到线程的内存映射区域,从而计算的实际使用情况。 具体步骤如下: - 打开 `/proc/<pid>/task/<tid>/maps` 文件。 - 查找包含 `[stack]` 的行,该行描述了线程的内存范围。 - 计算的起始地址和结束地址之间的差值,即可得到大小。 示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> void get_stack_size(pid_t pid, pid_t tid) { char filename[256]; snprintf(filename, sizeof(filename), "/proc/%d/task/%d/maps", pid, tid); FILE *fp = fopen(filename, "r"); if (!fp) { perror("fopen"); return; } char line[512]; while (fgets(line, sizeof(line), fp)) { if (strstr(line, "[stack]") != NULL) { unsigned long start, end; sscanf(line, "%lx-%lx", &start, &end); printf("Stack size: %lu bytes\n", end - start); break; } } fclose(fp); } int main() { pid_t pid = getpid(); pid_t tid = syscall(__NR_gettid); get_stack_size(pid, tid); return 0; } ``` 上述代码展示了如何通过解析 `/proc` 文件系统来获取当前线程大小[^1]。 #### 2. 使用 `pthread_attr_getstacksize` 如果需要获取创建线程时设置的大小,可以使用 `pthread_attr_getstacksize` 函数。此函数可以从线程属性对象中提取大小信息。需要注意的是,这种方法仅适用于已知线程属性对象的情况。 示例代码: ```c #include <pthread.h> #include <stdio.h> void* thread_function(void* arg) { return NULL; } int main() { pthread_t my_thread; pthread_attr_t thread_attr; size_t stack_size; pthread_attr_init(&thread_attr); pthread_attr_setstacksize(&thread_attr, 8 * 1024 * 1024); // 设置大小为8MB pthread_create(&my_thread, &thread_attr, thread_function, NULL); pthread_attr_getstacksize(&thread_attr, &stack_size); printf("Thread stack size: %zu bytes\n", stack_size); pthread_join(my_thread, NULL); pthread_attr_destroy(&thread_attr); return 0; } ``` 这段代码展示了如何通过 `pthread_attr_getstacksize` 获取线程大小[^2]。 #### 3. 使用 `ulimit -s` 查看默认大小 对于主线程,默认大小可以通过 `ulimit -s` 命令查看。然而,子线程大小通常由创建时指定,因此需要单独设置或查询。如果未显式设置子线程大小,则其默认值可能与主线程一致。 示例命令: ```bash ulimit -s ``` 输出结果以 KB 为单位表示的最大大小。例如,输出 `8192` 表示默认大小为 8MB[^3]。 #### 注意事项 - 子线程栈空间是从堆中分配的,因此需要明确指定大小,否则可能导致未定义行为。 - 实时监控线程使用率可能需要结合工具如 `gdb` 或 `valgrind` 进行深入分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值