Optimizing Heap Space in C++: Significance of Memory Management(Memory Leak)

Raj Vaibhav
4 min readDec 28, 2023

--

A program in execution is known as a process. When a program is in execution, the different parts of the process in memory are assigned mainly under the 4 categories:

1) Heap

2) Stack

3) Data ( Static/Global)

4) Code instruction(Text)

Source: Image by author

When an instruction needs memory during runtime it uses the heap space. Memory from the HEAP pool is allocated to the required instruction.

When a function is created in a program, the function call and all its local details such as parameters, and local variables and objects are stored in the STACK memory.

All the static and global variables in a program are stored in the DATA section of the memory.

And, all the code instructions are stored in the CODE INSTRUCTION or TEXT section of the memory

Let’s delve into the dynamics of a function and its local variables during invocation. When a function is called, its information is placed in the stack, and a corresponding stack frame is allocated. At any given moment, the instructions of the function at the top of the stack are executed until it either returns or completes its execution. Once a function finishes its execution, the memory allocated to its local variables, objects, and parameters (encapsulated in the stack frame) is automatically freed up in C++, ensuring efficient memory management

#include<iostream>
using namespace std;

void squareAndCubeNumber(int num){

int ar[2] = {num*num,num*num*num};

cout<<ar[0] << " "<< ar[1]<<"\n";

/*

logic to use square and cub to reach a result

*/

}
int main(){
squareAndCubeNumber(2); // invoke-1
squareAndCubeNumber(3); // invoke-2
squareAndCubeNumber(4); // invove-3
}
Source: Image by author

In the above code, when invoke-1 occurs it is allocated to the stack frame, and array ar[] is stored inside the stackframe. As the execution of the squareAndCubeNumber() function completes, the space allocated in the stack also gets deallocated i.e. memory automatically gets free by the compiler. The same happens when invoke-2 and invoke-3 get called.

However, this is not the case when memory is dynamically allocated to a variable using the ‘malloc()’ or ‘new’ keyword in C++. For this comes the question:

“ Why Destructor should be called for the objects created dynamically using the ‘new’ keyword or malloc function in C++? ”

Destructor can be said opposite of constructor as it destroys/ frees up the space allocated to the objects when its purpose is fulfilled. It is defined by the class name prefixed with the ‘~’ symbol. Destructor is automatically invoked when the function ends or it can be explicitly invoked by the ‘delete’ keyword.

In C++, dynamically allocated memory does not automatically free up. Inefficiently written code can lead to the accumulation of unused and garbage memory in the heap pool, causing a “Memory Leak.” This, in turn, restricts the allocation of space for new objects and hinders program execution.

Therefore, it becomes necessary to free up the space using the ‘delete’ keyword at the correct position in the program.

#include<iostream>
using namespace std;

void squareAndCubeNumber(int num){
int* ar = new int[2];
int square = num*num;
int cube = square * num;

ar[0] = square;
ar[1] = cube;

cout<<ar[0] << " "<< ar[1]<<"\n";

/*

logic to use square and cub to reach a result

*/

delete(ar);

}
int main(){

squareAndCubeNumber(2); // invoke-1
squareAndCubeNumber(3); // invoke-2
squareAndCubeNumber(4); // invoke-3

}

In the provided code, when the invoke-1 function is called, an array ‘ar[]’ is stored in the heap memory. Without ‘delete(ar)’ in the code, after invoke-1 completes, ‘ar[]’ remains in the heap memory. This situation persists for invoke-2 and invoke-3, where new space is allocated for ‘ar[],’ leading to inefficient memory usage.

However, including ‘delete(ar)’ in the code ensures that the space occupied by ‘ar[]’ is deallocated when the delete statement is encountered in the function. This results in efficient memory optimization, as the allocated space is freed up after the function execution, preventing unnecessary memory consumption in the heap.

In Java, this unused dynamic memory allocation gets automatically handled by the ‘Garbage Collector’.Therefore, there is no need to explicitly deallocate memory in Java.

Thank you!
I hope you enjoyed reading. :)

--

--

Raj Vaibhav

Computer Science Engineer |Programmer|Interested in Coding and various technologies such as Blockchain, NFTs, Artificial Intelligence, Machine learning, etc.