In Linux/GLIB/multithreaded environment, the default stack size of the threads is got by the pthread library from getrlimit() and the RLIMIT_STACK
parameter. In a shell you can get this value with a command like:
$ ulimit -s
8192
The above result is in kilobytes. Hence, the default thread stack size on my system is 8 MB of virtual memory.
Let's consider the following program creating one thread:
#include <pthread.h>
#include <unistd.h>
static void *thd(void *p)
{
pause();
return NULL;
}
int main(){
pthread_t tid;
pthread_create(&tid, NULL, thd, NULL);
pthread_join(tid, NULL);
return 0;
}
Let's compile and run it:
$ gcc pg.c -o pg -lpthread
$ ./pg &
As a stack is by default preceded by a red zone page (i.e. a page with no read/write access rights) to detect stacks overflows, the stack of the threads can be viewed in /proc/<pid>/smaps:
$ cat /proc/`pidof pg`/smaps
[...]
7fd503787000-7fd503788000 ---p 00000000 00:00 0
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
[...]
7fd503788000-7fd503f88000 rw-p 00000000 00:00 0
Size: 8192 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 8 kB
Pss: 8 kB
[...]
The above snippet of the output shows first the 4 KB long red zone and right after the 8 MB long thread's stack. The RSS field shows the actual RAM consumed by the thread as according to the lazy allocation feature of Linux: only touched pages in virtual memory trigger actual RAM pages allocations. Here it is 8 KB. This consumption is the internal pthread's task control block (TCB) of the thread + miscellaneous internal information.
Let's kill the preceding program:
$ kill `pidof pg`
[2]+ Terminated ./pg
Let's add some local variable in the thread. We write into them to trigger an actual RAM allocation:
#include <pthread.h>
#include <unistd.h>
#include <string.h>
static void *thd(void *p)
{
char buffer[8192];
// Force the physical allocation of the corresponding stack space
memset(buffer, 0, sizeof(buffer));
pause();
return NULL;
}
int main(){
pthread_t tid;
pthread_create(&tid, NULL, thd, NULL);
pthread_join(tid, NULL);
return 0;
}
Compilation and run:
$ gcc pg.c -o pg -lpthread
$ ./pg &
[2] 38167
The memory map shows a bigger RSS equal to 16 KB:
$ cat /proc/`pidof pg`/smaps
[...]
7f7e61244000-7f7e61245000 ---p 00000000 00:00 0
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
[...]
7f7e61245000-7f7e61a45000 rw-p 00000000 00:00 0
Size: 8192 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 16 kB
Pss: 16 kB
[...]
The 16 KB are actually the 8 KB seen above for the internal pthread information plus the 8 KB of the buffer
local variable of the thread.
Hence we have seen a method to catch the actual stack consumption of the threads of a process: look at the RSS of the corresponding memory zone in the process memory map.
PS: When sizing the stack of a thread, don't forget to allocate space for the signal handling as the handler is executed on the receiving thread's stack. The value MINSIGSTKSZ is defined to be the minimum stack size for a signal handler (cf. <signal.h>). Otherwise define an alternate stack for signals: cf. sigalstack()