2

At what struct size should I consider allocating on the heap / free store using new keyword (or any other method of dynamic allocation) instead of on the stack?

10 bytes? 20 bytes? 200 bytes? 2KB? 2MB? Never?

Even if I wanted to pass it around by pointer, I could still take a reference from the stack variable. I understand that a stack variable will disappear at the end of the scope and dynamically allocated variables will not. I can deal with that either way, but so far I've not found any guidance for when to allocate dynamically. Sure, avoid stack overflow by not putting too much on the stack... but how much is too much?

Any guidance would be appreciated.

Alasdair
  • 13,348
  • 18
  • 82
  • 138
  • 1
    IMO you should avoid `new` (and `new[]`) as much as possible. If you really need a pointer then use a *smart pointer* like [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) or [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) (depending on the ownership semantics needed), or [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) if you need a "dynamic array" (i.e. instead of `new[]`). – Some programmer dude Apr 14 '21 at 09:01
  • Stack has a limited size. you probably won't be able to allocate 2MB on stack. – user1810087 Apr 14 '21 at 09:01
  • If the lifetime of the objects exceeds the current scope, then you have to use `new/malloc`. In all other cases, I would try to use a local object, especially if it's small. A local buffer to read a file of 4kb, I usually put on the stack. Reading the whole file into a stack variable may be too much. So the clear answer is, it depends... – Devolus Apr 14 '21 at 09:02
  • And if you have a single structure with sizes more than a few hundred bytes to a couple of KiB, then I'd argue that you have a design problem and you should go back to the requirements and their analysis to find a better design that doesn't need such large structures. – Some programmer dude Apr 14 '21 at 09:05
  • 1
    *how much is too much?* .. That would presumably depend on the system your software is running on. For a new(ish) PC, running a 64-bit OS like Windows 10 or macOS, then using (say) 16k of stack is fine; but for an embedded 8-bit microprocessor, that would cause issues. And there is a lot of 'spectrum' in between those extremes. – Adrian Mole Apr 14 '21 at 09:06
  • 1
    Stack size depends on your platform. Some have 8MB by default, some have 1MB, some have 64KB. I've even worked on one that had a stack size of 256 bytes. – Eljay Apr 14 '21 at 09:07
  • Maybe interesting information: https://stackoverflow.com/q/18923339/1810087 – user1810087 Apr 14 '21 at 09:11
  • @Eljay Yes but that's 8MB for the entire stack. If this is part of a library then I can't just happy-go-lucky allocate large structs everywhere and use up all the stack space. My question is for what is a reasonable cut off. – Alasdair Apr 14 '21 at 09:12
  • 2
    As a guide, the MSVC static analyser (for 64-bit builds) gives warnings for functions that use more than 16k of stack space (by default) - the setting is `/analyze:stacksize '16384'` – Adrian Mole Apr 14 '21 at 09:13
  • @AdrianMole that is useful as a reference, thanks! If I don't get a better answer my gut tells me 196 bytes is reasonable/safe to put on the stack for 1 variable in 1 function, and any more I'll probably allocate it out into the wild. – Alasdair Apr 14 '21 at 09:17
  • The answer is going to be "depends". It depends on the platform, type of your project, perf requirements, etc. etc. – Aykhan Hagverdili Apr 14 '21 at 10:00
  • This question really solicits opinions. There is no real answer. As a matter of style, and because I'm predominantly working with applications in a Windows desktop environment, I will happily stack-allocate things like arrays of `wchar_t` that might have up to around 2K entries. But that's because I know the default Windows stack for threads is around 1MB. And when I'm doing this it's the exception rather than the rule. In general any objects I place on the stack tend to be smaller than this. In this environment, a function that puts kilobytes of data on the stack should be red-flagged. – paddy Apr 14 '21 at 10:49

2 Answers2

1

To actually answer the question, you'll need to know:

  • How big the stack is. This is often configurable at a compile-time, but may be capped by the target platform.

  • What is on the stack already. This knowledge is obtainable either by using deterministic call graph or by making decision actively, based on the current value of the stack pointer.

Without all of the above, any passive decision would be a gamble. Which also means that it's a gamble by default — indeed, in most cases we have to trust the compiler developers to understand how much of a stack space a "typical" program would need, and that our views on "typical" programs do align well and often.

In the long term, just like with any optimization problem, put your bets on measuring the overall performance and testing edge cases that may cause the stack overflow.

Shadows In Rain
  • 1,140
  • 12
  • 28
  • You've answered this question as if I have a specific problem that I need to try to solve... the question I asked is one that *everyone* should be asking, no? And of course it depends on the size of the stack and what is on the stack, that goes without saying. – Alasdair Apr 14 '21 at 09:54
  • 1
    @Alasdair You have asked for guidance, there is guidance I can offer. If you want specific thresholds, you have to provide specific context (aka you have a problem you are trying to solve): compiler, settings, platform, profiling stats. Otherwise, your comments suggest that your question meant to be too broad or opinion-based. – Shadows In Rain Apr 14 '21 at 10:40
0

(Note. I probably should have searched before answering, but this question is essentially a duplicate of How much stack usage is too much?, nevertheless, here is my opinion on it.)

If you intend to keep a large buffer around for an extended period of time, then you should allocate it on the heap.

If you are in a recursive function, then allocating large buffers on the stack can quickly lead to problems.

Personally, I would keep buffers below ~4KiB on the stack and allocate larger buffers on the heap, unless you have a good overview of your program, and more specifically, how and where your functions are called.

That being said, if you constantly create and destroy buffers, consider putting them on the stack.

(If you are working on an embedded system, then that's a very different story.)

asynts
  • 2,213
  • 2
  • 21
  • 35