1 Memory Allocators 101 Write A Simple Memory Allocator
Keira Mcduffie edited this page 2 days ago
This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.


We'll implement malloc(), calloc(), realloc() and free(). This is a beginner stage article, so I can't spell out each element. This memory allocator will not be quick and efficient, we won't modify allotted memory to align to a page boundary, but we are going to construct a memory allocator that works. If you wish to have a look on the code in full, take a look at my github repo memalloc. Before we get into constructing the memory allocator, you have to be conversant in the memory layout of a program. A process runs inside its own virtual handle area thats distinct from the digital address spaces of different processes. As you can see in the image, the stack and the heap develop in the alternative instructions. That is, brk factors to the top of the heap. Now if we wish to allocate extra memory within the heap, we need to request the system to increment brk.


Equally, to release memory we have to request the system to decrement brk. Assuming we run Linux (or a Unix-like system), we could make use of sbrk() system name that lets us manipulate this system break. Calling sbrk(0) provides the current address of program break. Calling sbrk(x) with a constructive worth increments brk by x bytes, as a result allocating memory. Calling sbrk(-x) with a unfavourable value decrements brk by x bytes, in consequence releasing memory. To be trustworthy, sbrk() just isn't our greatest buddy in 2015. There are higher alternatives like mmap() out there in the present day. It could can solely grow or shrink in LIFO order. However, the glibc implementation of malloc still makes use of sbrk() for allocating memory thats not too huge in dimension. So, we'll go ahead with sbrk() for our easy memory allocator. The malloc(size) function allocates size bytes of memory and returns a pointer to the allotted memory. Within the above code, we name sbrk() with the given measurement.


On success, measurement bytes are allotted on the heap. That was easy. Wasnt it? The difficult half is freeing this Memory Wave Audio. The free(ptr) function frees the memory block pointed to by ptr, which will need to have been returned by a previous call to malloc(), Memory Wave calloc() or realloc(). But to free a block of memory, the primary order of business is to know the dimensions of the memory block to be freed. In the present scheme of issues, this isn't attainable as the size info shouldn't be stored wherever. So, we must find a method to store the scale of an allotted block someplace. Furthermore, we'd like to know that the heap memory the working system has supplied is contiguous. So we are able to solely release memory which is at the tip of the heap. We cant launch a block of memory within the middle to the OS. Imagine your heap to be something like an extended loaf of bread that you may stretch and shrink at one finish, however you have to maintain it in one piece.


To deal with this situation of not having the ability to launch memory thats not at the tip of the heap, we'll make a distinction between freeing memory and releasing memory. From now on, freeing a block of memory does not essentially imply we release memory back to OS. It simply signifies that we keep the block marked as free. This block marked as free may be reused on a later malloc() name. Since Memory Wave not at the top of the heap cant be released, that is the only approach ahead for us. 2. Whether or not a block is free or not-free? To retailer this data, we will add a header to every newly allocated memory block. The thought is simple. We use this memory house returned by sbrk() to fit in both the header and the precise memory block. The header is internally managed, and is stored fully hidden from the calling program. We cant be fully sure the blocks of memory allotted by our malloc is contiguous.


Imagine the calling program has a foreign sbrk(), or theres a piece of memory mmap()ed in between our memory blocks. We additionally need a option to traverse via our blocks for memory (why traverse? we are going to get to know when we glance on the implementation of free()). So to maintain observe of the memory allocated by our malloc, we'll put them in a linked checklist. Now, lets wrap the complete header struct in a union along with a stub variable of dimension sixteen bytes. This makes the header end up on a memory tackle aligned to sixteen bytes. Recall that the size of a union is the larger measurement of its members. So the union ensures that the end of the header is memory aligned. The end of the header is where the precise memory block begins and subsequently the memory offered to the caller by the allocator will probably be aligned to 16 bytes.
reddit.com