17

It seems to me that everything that can be done with a stack can be done with the heap, but not everything that can be done with the heap can be done with the stack. Is that correct? Then for simplicity's sake, and even if we do lose a little amount of performance with certain workloads, couldn't it be better to just go with one standard (ie, the heap)?

Think of the trade-off between modularity and performance. I know that isn't the best way to describe this scenario, but in general it seems that simplicity of understanding and design could be a better option even if there is a potential for better performance.

Dark Templar
  • 6,323

11 Answers11

35

Heaps are bad at fast memory allocation and deallocation. If you want to grab many tiny amounts of memory for a limited duration, a heap is not your best choice. A stack, with its super-simple allocation / deallocation algorithm, naturally excels at this (even more so if it is built into the hardware), which is why people use it for things like passing arguments to functions and storing local variables - the most important downside is that it has limited space, and so keeping large objects in it, or trying to use it for long-lived objects, are both bad ideas.

Getting rid of the stack completely for the sake of simplifying a programming language is the wrong way IMO - a better approach would be to abstract the differences away, let the compiler figure out which kind of storage to use, while the programmer puts together higher-level constructs that are closer to the way humans think - and in fact, high-level languages like C#, Java, Python etc. do exactly this. They offer almost identical syntax for heap-allocated objects and stack-allocated primitives ('reference types' vs. 'value types' in .NET lingo), either fully transparent, or with a few functional differences which you must understand to use the language correctly (but you don't actually have to know how a stack and a heap work internally).

tdammers
  • 52,936
9

Simply put, a stack isn't a little bit of performance. It's hundreds or thousands of times faster than the heap. In addition, most modern machines have hardware support for the stack (like x86) and that hardware functionality for e.g. the call stack cannot be removed.

DeadMG
  • 36,914
8

No

The stack area in C++ is incredibly fast in comparison. I venture no experienced C++ developers would be open to disabling that functionality.

With C++, you have choice and you have control. The designers were not particularly inclined to introduce features that added significant execution time or space.

Exercising that choice

If you want to build a library or program which requires that every object is allocated dynamically, you can do that with C++. It would execute relatively slowly, but you could then have that 'modularity'. For the rest of us, the modularity is always optional, introduce it as needed because both are required for good/fast implementations.

Alternatives

There are other languages which require that storage for each object is created on the heap; it is quite slow, such that it compromises designs (real world programs) in a way that is worse than having to learn both (IMO).

Both are important, and C++ gives you the power use both effectively for each given scenario. Having said that, the C++ language may not be ideal for your design, if these factors in your OP are important to you (for example, read up on higher level languages).

justin
  • 2,033
6

Then for simplicity's sake, and even if we do lose a little amount of performance with certain workloads, couldn't it be better to just go with one standard (ie, the heap)?

Actually the performance hit is likely to be considerable!

As others have pointed out stacks are an extremely efficient structure for managing data that obeys LIFO (last in first out) rules. Memory allocation/freeing on the stack is usually just a change to a register on the CPU. Changing a register is almost always one of the fastest operations a processor can perform.

The heap is usually a fairly complex data structure and allocating/freeing memory will take many instructions to do all the associated bookkeeping. Even worse, in common implementations, every call to work with the heap has to the potential to result in a call to the operating system. Operating system calls are very time consuming! The program typically has to switch from user mode to kernel mode, and whenever this happens the operating system may decide that other programs have more pressing needs, and that your program will need to wait.

5

Simula used the heap for everything. Putting everything on the heap always induces one more level of indirection for local variables, and it puts additional pressure on the Garbage Collector (you have to take into account that Garbage Collectors really sucked back then). That's partly why Bjarne invented C++.

fredoverflow
  • 6,954
4

Stacks are extremely efficient for LIFO data, such as the meta-data associated with function calls, for instance. The stack also leverages inherent design features of the CPU. Since performance at this level is fundamental to just about everything else in a process, taking that "small" hit at that level will propagate very widely. In addition, heap memory is moveable by the OS, which would be deadly to stacks. While a stack can be implemented in the heap, it requires overhead that will affect literally every piece of a process at the most granular level.

kylben
  • 2,318
2

"efficient" in terms of you writing code maybe, but certainly not in terms of your software efficiency. Stack allocations are essentially free (it takes only a few machine instructions to move stack pointer and reserve space on the stack for local variables).

Since stack allocation takes almost no time, an allocation even on a very efficient heap will be 100k (if not 1M+) of times slower.

Now imagine how many local variables and other data structures a typical application uses. Every single little "i" that you use as a loop counter being allocated a million times slower.

Sure if the hardware is fast enough, you could write an application that only uses heap. But now imaging what kind of application you could write if you took advantage of heap and used the same hardware.

DXM
  • 20,022
2

You might have an interest in "Garbage Collection is Fast, but a Stack is Faster".

http://dspace.mit.edu/bitstream/handle/1721.1/6622/AIM-1462.ps.Z

If I read it correctly, these guys modified a C compiler to allocate "stack frames" on the heap, and then use garbage collection to de-allocate the frames instead of popping the stack.

Stack-allocated "stack frames" outperform heap-allocated "stack frames" decisively.

Bruce Ediger
  • 3,535
1

How is the call stack going to work on a heap? Essentially, you would have to allocate a stack on the heap in every program, so why not have the OS+hardware do that for you?

If you want things to be really simple and efficient, just give the user their chunk of memory and let them deal with it. Of course, nobody wants to implement everything their self and that is why we have a stack and a heap.

Pubby
  • 3,390
1

Both stack and heap are required. They are used in different situations, for example:

  1. Heap allocation has a limitation that sizeof(a[0])==sizeof(a[1])
  2. Stack allocation has a limitation that sizeof(a) is compile-time constant
  3. Heap allocation can do loops, graphs etc complex data structures
  4. Stack allocation can do compile-time sized trees
  5. Heap requires tracking of ownership
  6. Stack allocation and deallocation is automatic
  7. Heap memory can be easily passed from one scope to another via pointers
  8. Stack memory is local to each function and objects need to be moved to upper scope to extend their lifetime(or stored inside objects instead of inside member functions)
  9. Heap is bad for performance
  10. Stack is pretty quick
  11. Heap objects are returned from functions via pointers that take ownership. Or shared_ptrs.
  12. Stack objects are returned from functions via references that do not take ownership.
  13. Heap requires matching every new with correct kind of delete or delete[]
  14. Stack objects use RAII and constructor initialization lists
  15. Heap objects can be initialized any point inside a function, and cannot use constructor parameters
  16. Stack objects use constructor parameters for initialization
  17. Heap uses arrays and array size can change on runtime
  18. Stack is for single objects, and size is fixed on compile-time

Basically the mechanisms cannot be compared at all because so many details are different. The only thing common with them is that they both handle memory somehow.

tp1
  • 1,932
  • 11
  • 10
1

Modern computers have several layers of cache memory in addition to a large, but slow, main memory system. One can make dozens of accesses to the fastest cache memory in the time required to read or write one byte from the main memory system. Thus, accessing one location a thousand times is much faster than accessing 1,000 (or even 100) independent locations once each. Because most applications repeatedly allocate and deallocate small amounts of memory near the top of the stack, the locations on the top of the stack get used and re-used an enormous amount, such that the vast majority (99%+ in a typical application) of stack accesses can be handled using cache memory.

By contrast, if an application were to repeatedly create and abandon heap objects to store continuation information, every version of every stack object that was ever created would have to be written out to main memory. Even if the vast majority of such objects would be completely useless by the time the CPU wanted to recycle the cache pages they started out in, the CPU would have no way of knowing that. Consequently, the CPU would have to waste a lot of time performing slow memory writes of useless information. Not exactly a recipe for speed.

Another thing to consider is that in many cases it's useful to know that an object reference passed to a routine will not be used once the routine exits. If parameters and local variables are passed via the stack, and if inspection of the routine's code reveals that it does not persist a copy of the passed-in reference, then the code which calls the routine can be sure that if no outside reference to the object existed before the call, none will exist afterward. By contrast, if parameters were passed via heap objects, concepts like "after a routine returns" become somewhat more nebulous, since if code kept a copy of the continuation, it would be possible for the routine to "return" more than once following a single call.

supercat
  • 8,629