59

Lately when I've been writing C or C++, I'll declare all my variables on the stack just because it's an option, unlike with Java.

However, I've heard that it's a bad idea to declare large things on the stack.

  1. Why exactly is this the case? I figure stack overflow is involved, but I'm not very clear on why that happens.
  2. How much stuff on the stack is too much?

I'm not trying to put 100MB files on the stack, just a dozen kilobyte arrays to use as string buffers or whatever. Is this too much stack usage?

(Sorry if duplicate, searching for stack kept giving references to Stack Overflow. There isn't even a call stack tag, I just used the abstract one.)

4
  • 2
    How do you "put 100MB files on the stack"? Buffer and container implementations (and similar like std::string) usually use the heap to store their payload.
    – Murphy
    Commented Feb 20, 2016 at 22:37
  • 2
    You can get away with a fair amount of stack usage per function/method until recursion is involved, then you're risking severely limiting your capabilities, vis-à-vis recursive depth, so within recursive functions, you want to use as little local variable / stack space as possible.
    – Erik Eidt
    Commented Feb 21, 2016 at 2:23
  • 3
    Notice that C & C++ are different. A local std::vector<int> variable won't eat a lot of stack space, most of the data being in heap. Commented Feb 21, 2016 at 14:00
  • 3
    @Murphy char d[100*1<<20]; fread(d, sizeof(char), 100*1<<20, fptr);
    – Ed.
    Commented Dec 28, 2021 at 5:33

4 Answers 4

53

It depends on your operating system. On Windows, the typical maximum size for a stack is 1MB, whereas it is 8MB on a typical modern Linux, although those values are adjustable in various ways. If the sum of your stack variables (including low-level overhead such as return addresses, stack-based arguments, return value placeholders and alignment bytes) in the entire call stack exceeds that limit, you get a stack overflow, which typically takes down your program without any chance at recovery.

A few kilobytes are usually fine. Tens of kilobytes is dangerous because it starts to sum up. Hundreds of kilobytes is a very bad idea.

5
  • 3
    Isn't the typical stack limit several megabytes (i.e. usually more than one, but probably less than a dozen) today in 2016? On my Linux desktop, it is 8Mbytes by default... Commented Feb 21, 2016 at 15:54
  • 3
    "On [...] Linux, the typical maximum size for a stack is 1MB" $ ulimit -a on my system returns among others stack size (kbytes, -s) 8192.
    – Murphy
    Commented Feb 21, 2016 at 17:51
  • musl has a default thread stack size of 128k (80k prior to 1.1.21). But OpenWrt which is musl based still have the 8mb by default Commented Jan 8, 2023 at 9:31
  • @BasileStarynkevitch I'm running Windows 10 on an Intel i5-13600k. I testing my cache size using a program written in Rust where I try to allocate a huge array of 64-bit numbers. Rust allocates arrays on the stack. My program starts to generate stack overflow errors somewhere between 0.95 MiB and 1 MiB. ( So that lines up with what Sebastian was saying. Commented Feb 10, 2023 at 22:27
  • For C#, I believe Span<T> a = n<256 ? stackalloc T[n] : new T[n] is a good pattern for primitive types, which would limit to 256 slots (max 2KiB for long, double) on stack and larger amounts go on heap. Minimum default stack size on .NET is 256KiB. See also: vcsjones.dev/stackalloc
    – geekley
    Commented Aug 17, 2023 at 2:28
22

The only valid answer is vague: "too much is when the stack overflows."

Unless you are in complete control over the implementation of every line of code between the program's entry point and the function in question, you can make no assumptions about how much stack is available. You cannot, for example, guarantee that calling this function will never cause a stack overflow:

void break_the_camels_back()
{
    int straw;
    ...
}

The default 8 MiB stack on modern Unixes is quite a lot of room as stacks go, especially to someone like me who's enough of a geezer to remember CPUs with 8-bit stack pointers. The practical reality is that you're unlikely to blow through it without trying. If you do, exceeding the stack limit is usually considered a segmentation violation, and systems with enough memory management to detect it will send a SIGSEGV when it happens.

You do have a couple of options. First is to not guess how much stack is available and ask the system. Anything conforming to POSIX will have a getrlimit(2) function that will tell you the upper limit. RLIMIT_STACK is the specific limit you want. The second is to monitor how much stack your programs are using and make decisions about automatic variables vs. dynamic memory allocation based on that. There are, as far as I know, no standard functions to determine how much of the stack is used, but programs like valgrind can analyze it for you.

1
  • Any suggestions for monitoring stack sizes in Windows applications?
    – julealgon
    Commented Feb 24, 2021 at 21:48
9

If you allocate an array of say 10,000 bytes on the stack, then that array is limited in size. 10,000 may be a lot, but if you need 10,001 bytes then your program can crash or worse. So in this situation, you want something that adapts to the size you need, and that something won't be on the stack.

Fixed size arrays for string buffers on the stack are not a problem because they keep memory on the stack, they are a problem because fixed size buffers are a fatal problem waiting to happen.

But if you use C++, and declare for example a std::string or a std::vec on the stack, then what is on the stack will be actually of a fixed and small size. The actual data will be stored on the heap. You can store a million characters in a std::string instance, and it will only take a very small amount of data (typically 8 to 24 bytes, depending on implementation) on the stack, and a million bytes on the heap.

4

Well 1 MB is a good estimate for *nix . Recursion may be a major reason for stack overflow in combination with stack allocations. However , in most cases the god objects that would superficially seem too huge to be placed on stack are designed well to manage their internal memory on the heap and use the stack only as a way to automatically be destructed when the stack is popped . The destructor will free the huge chunks of memory internally managed. The std containers are designed that way , and the shared/unique pointers are designed that way as well.

The important thing is to not allocate large chunks of raw mem on stack like char [1024 * 1024] and to design classes to wrap heap allocations and use the stack only for the convenience of automatically calling the destructor.

Not the answer you're looking for? Browse other questions tagged or ask your own question.