Question

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.)

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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.

Licensed under: CC-BY-SA with attribution
scroll top