Introduction to Dynamic Memory Allocation

Introduction: We know that a program is a collection of instructions written in a programming language. It also known as source code and it cannot be executed directly. We need to compile it to generate the object code which is then linked to the libraries used in the actual code to generate the final executable. The executable, when run, is created as a process which resides in memory and consists of various segments.

Memory Layout of a Process: The following diagram explains various segments of a process created in memory:

In this layout, we have the following segments: 1. Text segment: - This segment consists of executable instructions and is placed at the bottom. - It is read-only. - It is a shared segment as multiple executions of the same program are possible. 2. Initialized segment: - This is also called and consists of global and variables that are initialized. - It is further divided into read-only and read-write areas. 3. Uninitialized segment: - This is also called “block started by symbol (bss)”. - It consists of global and static variables that are initialized to zero or that do not have explicit initialization. 4. Stack segment: - This segment consists of all local variables, function calls and parameters. - It grows from top to bottom which means the variables create first will have higher addresses while those created later will have lower addresses. - It is used for static memory allocation. 5. Heap segment: - This segment is used for allocating memory dynamically. - It grows from top to bottom i.e. memory allocation happens from lower address to higher address. We have a command called size that can be used to know the sizes of text segment, data segment and BSS. If you observe the following code, we have one and one static variable – both uninitialized. If you compile and observe the output of size command, the size of text segment is 1129 bytes while the size of data segment is 540 bytes and the size of BSS is 12 bytes. Though there are no initialized global and static variables, the size of data segment is 540 bytes. This is because there will be some global and static variables defined in the libraries attached to the executable. Similarly, the BSS is of 12 bytes though we have one global integer and one static integer accounting for 8 bytes. The remaining 4 bytes would be related to the uninitialized data from the attached libraries.

If you initialize the global variable g, four bytes will be moved from the BSS to data segment.

If you initialize the static integer variable “local”, it will move four more bytes to the data segment.

Let us understand how memory spans across multiple segments using the following program:

For this program, the memory layout is given in the following diagram:

Static Memory Allocation: Whenever we define a , it is defined in stack segment and memory is allocated statically. A memory allocated statically cannot be extended. Neither can we release the memory that is allocated statically. In some cases, we may need the framework to dynamically allocate or dynamically release memory as needed. In other words, we need the ability to change the memory already allocated.

Dynamic Memory Allocation: The following cases give an idea on the need for dynamic manipulation of memory allocation: - Let us an array of 10 elements; we have filled in all the elements and we need more space. Can we extend it? - We have reserved space for 100 elements but we just 5 elements. Can we free up the unwanted memory? In the first case, we need to extend the memory while the second warrants release of unused memory. In other words, we need the ability to dynamically allocate or dynamically release memory according to the need. This is called dynamic memory allocation. These scenarios cannot be worked out in stack segment. On the other hand, Heap will help us do the dynamic allocation and dynamic release of memory.

C Library Functions: Dynamic memory allocation is made possible through the framework provided a set of library functions that are built on top of a few system calls such as brk(), sbrk() and mmap(). Following library functions are used in dynamic memory allocation: . malloc() – to allocate given block of memory (without initialization) . calloc() – to allocate given block of memory (with initialization to 0) . realloc() – to extend the allocated block of memory . free() – to free up the allocated memory