pthread的默认堆栈大小


24

据我了解,Linux上pthread的默认堆栈大小为16K。我在64位Ubuntu安装上得到了奇怪的结果。

$ ulimit -s
8192

也:

pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize);
printf("Thread stack size = %d bytes \n", stacksize);

Prints
    Thread stack size = 8388608 bytes

我非常确定堆栈大小不是“ 8388608”。有什么事吗


7
我认为8388608 / 1024 = 8192
cuonglm

6
您正在考虑每个线程16k 内核堆栈。与用户空间堆栈内存完全分开的问题。内核堆栈之所以很小,是因为它们无法分页或延迟分配,并且必须是物理内存中的连续页面。 elinux.org/Kernel_Small_Stacks。对于i386来说,拥有非常大的总线程数可能是一个问题,因为i386的地址空间有限,尤其是对于默认为32位的8k堆栈。
彼得·科德斯

Answers:


21
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

stacksize属性应定义为创建的线程堆栈分配的最小堆栈大小(以字节为单位)。

在您的示例中,堆栈大小设置为8388608字节,对应于8MB,由命令ulimit -s So that match 返回。

根据pthread_create()说明:

Linux / x86-32上,新线程的默认堆栈大小为2 MB。在NPTL线程实现下,如果程序启动时的 RLIMIT_STACK软资源限制具有“ unlimited”以外的任何其他值,则它将确定新线程的默认堆栈大小。使用pthread_attr_setstacksize(3),可以在用于创建线程的attr参数中显式设置堆栈大小属性,以获取默认值以外的堆栈大小。

因此,可以通过上面的set函数或ulimitsystem属性来设置线程堆栈的大小。对于您所指的16k,目前尚不清楚您在哪个平台上看到过,和/或是否为此设置了任何系统限制。

请参见pthread_create页面此处有一些有趣的示例。


47

实际上,您的虚拟堆栈大小 8388608字节(8 MB)。当然,很自然地得出这样的结论是不正确的,因为当99%的时间可能需要几个KB时,每个线程要为其堆栈消耗的内存是荒谬的。

好消息是,您的线程仅使用其实际需要的物理内存量。这是操作系统通过使用处理器中的硬件内存管理单元(MMU)获得的神奇力量之一。这是发生了什么:

  1. 操作系统通过为线程设置MMU的页表,为堆栈分配8 MB的虚拟内存。这需要很少的RAM来仅保存页表条目。

  2. 当您的线程运行并尝试访问尚未分配物理页面的堆栈上的虚拟地址时,MMU会触发称为“页面错误”的硬件异常。

  3. CPU内核通过切换到特权执行模式(具有自己的堆栈)并在内核内部调用页面错误异常处理程序函数来响应页面错误异常。

  4. 内核将物理RAM的页面分配给该虚拟内存页面,然后返回到用户空间线程。

用户空间线程看不到任何工作。从它的角度来看,它只是像使用内存一样一直使用堆栈。同时,堆栈会自动增长(或不增长)以满足线程的需求。

MMU是当今计算机系统硬件的关键部分。特别是,它负责系统中的许多“魔术”,因此我强烈建议您了解有关MMU的功能以及一般而言虚拟内存的更多信息。另外,如果您的应用程序对性能敏感并且处理大量数据,则应了解TLB(MMU的页表缓存)如何工作,以及如何重组数据或算法以最大程度地提高TLB命中率。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.