How Linux’s Memory Allotment System Operates

We independently review everything we recommend. When you buy through our links, we may earn a commission.

Linux's Memory Allotment System Operates

Memory is required to execute all of the applications that are currently running on your system. The memory on a Linux computer is allocated and shared in what manner, exactly?

In order for a process to be executable on a computer, it must first be stored in the memory of the machine. In order to do this, a process in memory has to have a field allocated to it. Memory allocation is a crucial topic that should be carefully considered, particularly in the context of system and kernel designs.

Let’s go into the nitty-gritty of memory allocation in Linux so we can have a better understanding of what goes on behind the scenes.

How Is Memory Being Allotted Exactly?

The vast majority of software developers are not familiar with the specifics of this approach. However, if you are applying to be a system programmer, you need have a deeper understanding of this topic. When examining the allocation process, it is important to delve into certain specifics on Linux and the glibc library. These specifics are required in order to fully comprehend the allocation process.

Applications are required to submit a memory request to the operating system whenever they require memory. Naturally, a system call will be necessary in order to fulfill this request from the kernel. In user mode, it is not possible to allocate RAM on your own.

Memory allocation in the C programming language is the responsibility of the malloc() family of functions. In this context, the issue that has to be asked is whether or not the glibc method malloc() performs a direct system call.

Within the Linux kernel, there is no such thing as a system call named malloc. On the other hand, brk and mmap are the two system calls that may be used to satisfy the memory requirements of programs.

You might be asking which of these system calls glibc is using at this point given that you will be making memory requests in your application by using glibc methods. Both is the correct response.

The Very First Call to the System: brk

Each process has its own data field that is continuous. The brk system call is what is responsible for increasing the program break value and carrying out the process of allocation. The program break value is what establishes the limit of the data field.

When using this approach to allocate memory, memory is allocated relatively quickly; nevertheless, it is not always feasible to give back any excess space to the system.

Consider the following scenario: you use the malloc() function in conjunction with the brk system call to allocate five fields, each of which is 16 KB in size. It is not feasible to return the appropriate resource (deallocation) once you have completed the second of these fields, which means that the system will not be able to make use of it. Because if you lower the address value to show the point where your field number two starts, then with a call to brk, you will have completed deallocation for fields number three, number four, and number five, respectively.

The malloc implementation in glibc monitors the places that have been allocated in the process data field and then specifies to return it to the system with the free() function. This allows the system to use the free space for additional memory allocations and prevents memory loss from occurring in the scenario described above.

In other words, after the first five 16KB areas have been allocated, if the second area is returned with the free() function and another 16KB area is requested again after a while, the previous address is returned rather than expanding the data area through the use of the brk system call. This occurs in the event that the second area was returned with the free() function.

However, if the newly requested area is bigger than 16 KB, then the data area will be expanded by using the brk system call to allocate a new area since area two cannot be used. This is because area two cannot be utilized. Despite the fact that area number two is vacant, the application is unable to make use of it due to the significant size disparity. There is a phenomenon known as internal fragmentation that can occur as a result of situations such as this one. As a result of internal fragmentation, it is extremely unusual to utilise all of the memory’s components to their maximum potential.

Compiling and executing the following sample application can help clarify things for you:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
char *ptr[7];
int n;
printf(“Pid of %s: %d”, argv[0], getpid());
printf(“Initial program break : %p”, sbrk(0));
for(n=0; n<5; n++) ptr[n] = malloc(16 * 1024);
printf(“After 5 x 16kB malloc : %p”, sbrk(0));
printf(“After free of second 16kB : %p”, sbrk(0));
ptr[5] = malloc(16 * 1024);
printf(“After allocating 6th of 16kB : %p”, sbrk(0));
printf(“After freeing last block : %p”, sbrk(0));
ptr[6] = malloc(18 * 1024);
printf(“After allocating a new 18kB : %p”, sbrk(0));
return 0;

If you execute the program, you will see a result that is comparable to the one below when it is output:

Pid of ./a.out: 31990
Initial program break : 0x55ebcadf4000
After 5 x 16kB malloc : 0x55ebcadf4000
After free of second 16kB : 0x55ebcadf4000
After allocating 6th of 16kB : 0x55ebcadf4000
After freeing last block : 0x55ebcadf4000
After allocating a new 18kB : 0x55ebcadf4000

The following will be displayed as the output when brk is run through strace:

brk(NULL) = 0x5608595b6000
brk(0x5608595d7000) = 0x5608595d7000

As can be seen, the terminating address of the data field has been extended by 0x21000 since it was last modified. The number 0x5608595d7000 provides you with the information you need to comprehend this. Therefore, about 0x21000 bytes, or 132 kilobytes, of RAM was made available.

Here, we need to take into consideration two very significant aspects. The first issue is that the amount that was allotted was greater than what was mentioned in the sample code. Another question to consider is which line of code resulted in the brk call that was responsible for providing the allocation.

Address Space Layout Randomization: ASLR

If you keep running the sample application from earlier in this paragraph one after the other, you will see that the address values change each time. Increasing software security by making the address space shift randomly like this considerably complicates the job of security attacks and makes it more difficult for them to succeed.

On the other hand, in architectures with 32 bits, the address space is often randomized using eight of the available bits. Increasing the amount of bits will not be adequate since there will be a very little addressable region over the bits that are left. In addition, the usage of combinations consisting of only 8 bits does not make things sufficiently challenging for the attacker.

When 64-bit architectures are used, on the other hand, there are an excessive number of bits that may be assigned for the ASLR procedure. This results in the provision of a considerably bigger amount of randomness, which in turn results in an increased level of security.

Android-based smartphones are likewise powered by the Linux kernel, and the ASLR capability was not completely active until Android 4.0.3 and subsequent versions. Even if this is the only reason, it would not be incorrect to argue that a 64-bit smartphone offers a major benefit in terms of its level of security in comparison to 32-bit models.

If you use the following command to temporarily disable the address space layout randomization (ASLR) function, the preceding test program will appear to consistently return the same address value each time it is executed:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

It will be sufficient to write the value 2 instead of 0 in the same file in order to return it to the condition it was in before.

The Second System Call: mmap

On Linux, the mmap system call is the second one that is utilized for memory allocation. The open space in any part of the memory can be mapped to the address space of the process that is executing the mmap function thanks to the call.

When memory is allocated in such a manner, there is no means to prohibit the operation that occurs when you wish to return the second 16KB partition using the free() function, as demonstrated in the preceding example of brk. The process will no longer have access to the relevant memory segment after it has been removed from its address space. It is flagged as having been deactivated and then sent back to the system.

Memory must be allocated via brk rather than mmap due to the former’s excruciatingly glacial pace in comparison to that of the latter.

Because using mmap maps any vacant area of memory to the address space of the process, the contents of the allocated space are cleared off before the process is entirely finished. If the reset was not performed in this manner, the data that belonged to the process that had been using the relevant memory space might also be accessible by the following process, which was unconnected to the prior one. Because of this, it is hard to have a conversation on the security of systems.

Importance of Memory Allocation in Linux

Memory allocation is extremely significant, particularly in terms of optimization and security concerns. If you do not have a complete grasp of this issue, the security of your system may be compromised, as demonstrated in the instances given above.

Even ideas that are analogous to push and pop that are included in a variety of programming languages are founded on memory allocation functions. Both the process of programming embedded systems and the process of building a safe and optimal system architecture require a strong command of system memory and the ability to effectively utilise it.

If you are also interested in contributing to the development of the Linux kernel, you need become proficient in the C programming language first.

We will be happy to hear your thoughts

Leave a reply