36

As I understand, the default stack size for a pthread on Linux is 16K. I am getting strange results on my 64-bit Ubuntu install.

$ ulimit -s
8192

Also:

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

Prints
    Thread stack size = 8388608 bytes

I'm quite sure the stack size is not "8388608". What could be wrong?

2
  • 8
    I think 8388608 / 1024 = 8192.
    – cuonglm
    May 2, 2014 at 17:05
  • 10
    You're thinking of 16k per thread kernel stacks. Totally separate issue from user-space stack memory. kernel stacks are tiny because they can't be paged, or be lazy-allocated, and have to be contiguous pages in physical memory. elinux.org/Kernel_Small_Stacks. Having an extremely high number of total threads can be a problem for i386, where address-space is limited, especially with 8k stacks by default for 32-bit. Jul 8, 2017 at 5:09

2 Answers 2

71

Actually, your virtual stack size is 8388608 bytes (8 MB). Of course, it's natural to conclude that this can't be right, because that's a ridiculously large amount of memory for every thread to consume for its stack when 99% of the time a couple of KB is probably all they need.

The good news is that your thread only uses the amount of physical memory that it actually needs. This is one of the magical powers that your OS gets from using the hardware Memory Management Unit (MMU) in your processor. Here's what happens:

  1. The OS allocates 8 MB of virtual memory for your stack by setting up the MMU's page tables for your thread. This requires very little RAM to hold the page table entries only.

  2. When your thread runs and tries to access a virtual address on the stack that doesn't have a physical page assigned to it yet, a hardware exception called a "page fault" is triggered by the MMU.

  3. The CPU core responds to the page fault exception by switching to a privileged execution mode (which has its own stack) and calling the page fault exception handler function inside the kernel.

  4. The kernel allocates a page of physical RAM to that virtual memory page and returns back to the user space thread.

The user space thread sees none of that work. From its point of view, it just uses the stack as if the memory was there all along. Meanwhile, the stack automatically grows (or doesn't) to meet the thread's needs.

The MMU is a key part of the hardware of today's computer systems. In particular, it's responsible for a lot of the "magic" in the system, so I highly recommend learning more about what the MMU does, and about virtual memory in general. Also, if your application is performance sensitive and deals with a significant amount of data, you should understand how the TLB (the MMU's page table cache) works and how you can restructure your data or your algorithms to maximize your TLB hit rate.

3
  • 1
    Thank you! Amazing answer! Could you recommend books about MMU / virtual memory and how to maximize TLB hit rate?
    – likern
    May 9, 2021 at 20:33
  • 2
    I don't (yet) have any books in mind, but here's a good little paper I found through DuckDuckGo that explains quite well how the TLB works (part of a Comp Sci course from the University of Wisconsin-Madison, by the looks of it): pages.cs.wisc.edu/~remzi/OSTEP/vm-tlbs.pdf. That should give you enough to at least start reasoning about how your data layout and algorithms might affect your TLB hit rate. Seems like a great topic for another question. ;)
    – jtchitty
    May 15, 2021 at 4:04
  • @likern I would recommend Operating Systems: Three Easy Pieces goodreads.com/book/show/17374825-operating-systems. It has great discussion on virtual memory architecture, importance and performance characteristics of TLB and many more. In general, a great book on foundational OS topics. Oct 5, 2022 at 15:26
23
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

The stacksize attribute shall define the minimum stack size (in bytes) allocated for the created threads stack.

In your example, the stack size is set to 8388608 bytes which corresponds to 8MB, as returned by the command ulimit -s So that matches.

From the pthread_create() description:

On Linux/x86-32, the default stack size for a new thread is 2 megabytes. Under the NPTL threading implementation, if the RLIMIT_STACK soft resource limit at the time the program started has any value other than "unlimited", then it determines the default stack size of new threads. Using pthread_attr_setstacksize(3), the stack size attribute can be explicitly set in the attr argument used to create a thread, in order to obtain a stack size other than the default.

So the thread stack size can be set either via the set function above, or the ulimit system property. For the 16k you're referring to, it's not clear on which platform you've seen that and/or if any system limit was set for this.

See the pthread_create page and here for some interesting examples on this.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .