Memory Management in C++

Supun Kuruppu
8 min readSep 8, 2022

--

Managing memory is an important part of developing software. It is especially important in firmware development due to the resource constraint nature of those applications. In some programming languages like Python or Java, the entirety of the memory management process is done automatically, thus relieving the programmer of memory management. However, complete automation causes inefficiencies in the final program. In C/C++, which are the standard languages for firmware development, only a portion of the memory management process is automated. The programmer has to manage a portion of the memory management process to develop efficient, robust firmware solutions.

To understand how to manage memory in C++, it is essential to recognize the memory layout of C++ programs.

Memory Layout of C++ Programs

The memory layout of a C++ program is the arrangement of the memory that it gets assigned by the Operating System.

Figure 1: Memory layout of a C++ program

As depicted in figure 1, it consists of five main sections. They are arranged from higher memory addresses to lower memory addresses as shown.

1) Text/Code Segment :

This portion of the assigned memory contains all the executable instructions of the program. It is read-only and it is located below both the Stack and the Heap to prevent Heap and Stack overflows from causing an overwrite.

2) Initialized Data Segment

This section of the allocated memory contains all the global and static variables of the program that have been initialized to some value.

3) Uninitialized Data Segment

This part of the designated memory contains all the global and static variables of the program that have not been initialized to any value.

4) Stack

The Stack is a section of the allocated memory that contain data that are associated with the current scope of the program. As the name suggests, it follows a LIFO structure.

5) Heap

The Heap is also a section of the assigned memory that holds data. However, it has no association with the Heap data structure. It is a pile of memory locations that are available for the programmer to utilize.

Although there are five main sections in the layout of the allocated memory of a C++ program, there are only two portions that relate to the memory management that need to be done by the programmer, the Stack and the Heap.

Stack Memory

As mentioned previously, the Stack is a section of the assigned program memory that contains data associated with the current scope of the program until the scope’s completion. Furthermore, the collection of data relating to a specific scope in the Stack is called a “Stack frame”. In the case of nested scopes, the Stack frame of the nested scope is loaded on top of its parent’s Stack frame. Since the nested scope is executed to completion before its parent scope due to the sequential nature of programs, the Stack memory behaves according to the LIFO structure. Moreover, the Stack saves data in contiguous memory locations. Therefore, allocating data onto the Stack is extremely efficient, since only the Stack Pointer needs to be moved by the size of the data.

The Stack memory is relatively small. Each Stack frame is stored in this Stack’s allocated space and the amount of memory that needs to be assigned for each Stack frame is calculated during the program’s compilation. Once the program goes out of a specific scope, the Stack frame of that scope is deleted automatically and those memory locations become free for a new Stack frame. If the entire Stack gets occupied and the program instructions request Stack memory for a new Stack frame, the program throws a “Stack Overflow” error.

Demonstration

  • Allocating an integer on the Stack with the value 5

The “val” variable has been allocated to the Stack memory in the depicted memory location. Since the integer is 4 bytes, it is represented by four hexadecimal numbers.

  • Automatic deletion of out-of-scope variables

As soon as the program goes out of the “func” function where the “example_obj” is created, that object gets automatically deleted.

  • Allocating an integer array in the Stack
  • Contiguous nature of the Stack

The value of the variable “val” and the values of the array “num_array” are saved in contiguous memory locations.

  • Assembly code of allocating an integer and an integer array onto the Stack

It takes only one assembly instruction to allocate the integer variable on the Stack and three assembly instructions to allocate the integer array of length three on the Stack. Therefore, Stack allocation is extremely fast and efficient.

Heap Memory

The Heap memory is a part of the memory arrangement of a C++ program. However, it does not have any relation to the Heap data structure. Heap memory is a pile of memory locations that are available for the programmer’s use. Therefore, Heap memory is also known as a free store of memory.

Initially, when the program starts, a default size of memory is allocated as the Heap memory, but it is not fixed to that initial size. As the program progresses, if the programmer requests more Heap memory than what was initially allocated, the program will request more memory from the operating system for the Heap memory. Therefore, the Heap memory can grow during runtime. Hence, it is also referred to as Dynamic memory. Similarly, allocating data in the Heap memory is also termed dynamic memory allocation.

The process of allocating data in the Heap memory is also different from that of the Stack memory. One important difference is that the Heap memory does not store objects in contiguous memory locations. When the programmer allocates data in the Heap memory, the program initially scans the free list, which holds the unoccupied memory addresses in the Heap memory and lends available memory that is at least as large as the requested memory size. Subsequently, some administrative tasks such as marking the retrieved memory locations as occupied in the free list are performed by the program. Additionally, if the programmer requests memory that is greater than what is currently available in the Heap memory, the program needs to request the operating system for more memory, which is also a computationally intensive task. Therefore, allocating data in the Heap memory is substantially computationally expensive than allocation data in the Stack memory.

Another important detail in Heap memory allocation is that the programmer needs to manually free the allocated memory locations after its use. In the case where it is not performed, it is termed a Memory Leak. Accumulation of such memory leaks can lead to application failures due to the unavailability of more system memory (Heap overflow) or a vast slowdown in performance due to constant requests for more memory by the program.

Demonstration

  • Allocating an integer on the Heap with the value 5

The new keyword along with int datatype returns an integer pointer to the memory location on the Heap where the integer will be saved.

The delete keyword with the pointer to the Heap memory location where the object (data) is saved will free the allocated memory locations in the Heap.

  • Objects (Data) allocated on the Heap memory outliving the scope that it has been defined

The Example object does not get deallocated (deleted) when the program goes out of the “func” function’s scope.

The Example object gets deallocated (deleted) only when the programmer explicitly deallocates it.

  • Allocating an integer array on the Heap

The deallocation of an array in the Heap is done via the “delete[]” keyword.

The value of the variable “val” and the values of the array “num_array” are not saved in contiguous memory locations.

  • Assembly code of allocating an integer and an integer array in the Heap

It takes several assembly instructions for the allocation of an integer and an integer array.

  • Assembly code of deallocating an integer and an integer array in the Heap

Similarly, it also takes numerous assembly instructions for the deallocation of integers and integer arrays in the Heap.

Stack Memory vs Heap Memory

The Stack memory and the Heap memory differ in the memory allocation methodology. The following is a comparison of the two sections in the memory.

The programmer needs to decide whether to allocate data in the Stack or the Heap based on the requirements.

The Stack memory allocation and deallocation are extremely efficient. Therefore, in all possible scenarios, data should be allocated in the Stack to ensure optimal efficiency in the program. However, if the programmer requires the created objects (data) to outlive their defined scope, then they should be allocated to the Heap memory. Moreover, if the data are large, they should also be allocated in the Heap memory because the Stack memory is limited and fixed in size. Generally, the effect of the increased number of cache hits when data are stored in the Stack memory is not considered because in practice there should be millions of additional cache hits to have a practical effect on the program’s efficiency. However, the programmer should decide whether this general assumption is valid for the application that he/she is working on.

References

--

--