You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.8 KiB


When implementing the functionality of abstract data structures, it becomes necessary to have an array whose size is not known at compile time. This is problematic in languages like C and C++ where the size of an array must be known when compiling in order to calculate how bih the stack frame must be. The solution is to forgo having the array existing on the stack and not even dedicate space at compile time for the array. Instead, the array is created during runtime once the size of the array can be determined. This is known as dynamic memory allocation. A special region in a process's memory is dedicated for these kinds of allocations, called the heap, while a memory allocator keeps track of this space's usage. How the allocator handles memory that is no longer in use and situations in which a region must be resized depends on how it is implemented. In addition, the memory allocator has to balance how much memory that it uses for record keeping while also minimizing the amount of CPU cycles required to manage the memory region it has been given.

In ANSI C, the standard library provides a memory allocator for general purpose use in programs. Dynamic memory allocation is performed through the malloc() library call in which the caller passes the desired size of the allocation and it returns a pointer to the allocated memory region. It must be noted that malloc does not initalize the returned memory region with any value, so the caller must initalize the array itself. However, the standard library also provides the calloc() library call in which the allocated memory is initalized with zero in every byte. Resizing of an allocation is performed using the realloc() and reallocarray() library calls, which will either grow the allocation in place or move the allocation to a space in which the new size can fit. The program must signify to the allocator that an memory region is to be marked free through the free() libary call. Should it fail to notify the allocator that an allocation is no longer in use before all of its references go out of scope, it will become impossible to access the underlying data or use the space it took up; a memory leak.

Other languages' standard libraries can provide memory allocators or additional data structures for dynamic allocation using other techniques. Rather returning a pointer as a reference to the allocation, languages like C++ and Rust provide smart references that determines when the underlying memory allocation can be freed by detecting when all of its references have gone out of scope. Runtime languages like those running on the Java Virtual Machine or Microsoft's Common Language Interface also provide smart pointers, but wait to free the unused memory regions until a scheduled batch process occurs known as a garbage collection. Higher order languages like Python and Lua completely abstract away that dynamic allocation is occuring by only allowing abstract data structures to be created by the programmer, allowing for their implementation to handle the underlying allocations needed transparently.

In practice, abstract data structures do not allocate in the same way. It is possible to categorize them into two groups based on how they allocate. For data structures like vectors and smart strings, a single allocation is made at its creation and then resized as data is either added or removed. This is the first group. The second group consists of data structures like linked lists and trees, where many allocations and frees are requested, but each allocation is fixed in size. Rather than handling dynamic allocation request using one method, abstract data structures could instead give hints to the allocator as to what kind of allocations it should be making. Such an allocator could then be constructed to take advantage of these hints and optimize accordingly. This is what this paper aims to demonstrate.