How to Utilize Stack vs Heap Memory Allocation in C++
This article will explain several methods of how to utilize stack vs heap memory allocation in C++.
Difference Between Stack vs Heap Memory in C++
When we want to discuss the concepts of memory, it’s best to think in terms of systems where most common user programs run. Most user programs are run in an operating system environment, which manages hardware resources for us and takes care of various tasks that would be too complex or inefficient for a user program to handle. One of such tasks is to manage hardware memory directly. Thus, almost all operating systems provide special structures and functions to interact with the hardware memory. Two common concepts in the operating system-provided memory structures are stack and heap.
A stack is a memory region reserved for each running program in the system, and it operates in a LIFO manner. Namely, when the program starts executing the main
function, the latter gets its stack frame (a subset of stack memory), where local variables and function call return addresses are stored automatically. Once the main
calls another function, a new stack frame is created after the previous one in a continuous manner. The newest stack frame will store the local objects for the corresponding function and when it returns these memory gets unoccupied.
Note that the stack size is fixed on most systems by default but can be customized to a certain degree if the user has special needs. The size limitation of stack memory makes it suitable for small and mostly temporary objects. E.g., the default stack size for the user program in the Linux operation system is 8MB. It can be smaller than a single JPEG photo that a program may need to process, so the user has to use this space with diligent caution. Variables declared in the following code snippet are all stored on stack memory. As a general rule, every local variable is allocated on the stack if it does not have special specifiers like static
or volatile
.
#include <iostream>
using std::cout;
using std::endl;
int main() {
int var1;
int var2 = 123;
int arr1[4] = {1, 2, 3, 4};
int var3 = var2;
cout << var1 << endl;
cout << var2 << endl;
cout << var3 << endl;
return EXIT_SUCCESS;
}
Output:
0
123
123
On the other hand, there is a memory region called - heap (also referred to as free store
), where large objects can be stored and allocations made manually by the programmer during the run-time. These two features make the heap memory dynamic in nature, as its size does not need to be determined on compile-time or any moment during the program execution. The program can call special functions and request the allocations from the operating system. Note that the heap memory may seem infinite from the program’s perspective as it’s not limited to call another allocation function to request more memory. Although, the operating system manages the memory for all running processes; and it might decline new allocations when there is no more physical memory available.
The memory system in the operating system is quite complex and requires an understanding of various OS/hardware-specific concepts, so we only cover more than the bare minimum about heap and stack memories in this topic. Heap memory manual management in C++ language can be done using new
/delete
operators or malloc
/free
functions. Note that these functions work in a similar manner, where the user usually specifies the number of bytes to allocate, and it returns the address where the same amount of memory was allocated. The programmer can consequently operate on the given memory region as needed.
The next code sample demonstrates several cases of allocating the different objects on the heap memory. One important feature of manual memory management is to return the allocated memory region back to the operating system when it’s not needed anymore. The latter operation is done using delete
/free
calls corresponding to their allocation counterparts. If the program does not free the unneeded memory, there’s a risk that the operating system will run out of memory, and the program may be killed as a result. Notice, though, the previous problem is mostly expected to occur in long-running programs, and they are characterized as memory-leak bugs.
#include <iostream>
using std::cout;
using std::endl;
int main() {
auto var4 = new int;
cout << var4 << endl;
int *arr2 = new int[4];
auto arr3 = new int[4];
cout << arr2 << endl;
cout << arr3 << endl;
delete var4;
delete[] arr2;
delete[] arr3;
return EXIT_SUCCESS;
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook