thomasloven.com/pages/2012-07-02-Memory-Heap.md

111 lines
3.7 KiB
Markdown

layout: post
title: "Memory Heap"
subtitle: "Basic memory management 3/3"
tags: [osdev]
###Memory management part 3
I have previously ([Memory Page Stack](/blog/2012/06/Memory-Page-Stack),
[Recursive Page Directory](/blog/2012/06/Recursive-Page-Directory)) described
how I like to divide the memory management of a kernel into three parts. This
post regards the third part, which I like to call the heap.
###Memory Management
In fact, a memory heap is but one way of handling memory. I believe it's the
kind that is easiest to implement and understand (with one exception) but it is
a bit slow.
The main task of a memory manager is to reserve and hand out areas in memory
when asked. For example, a program may run _malloc(size)_ and get a pointer to
a memory area of the asked size. It can then do whatever it wants with this
memory area and can be sure that it will not be handed out again by _malloc_
before it has been returned by _free_.
Now, let's look at a few ways to do this.
###Linear allocation
The simplest possible memory manager just hands out a new address each time
_malloc_ is called and doesn't care when memory is freed.
:::c
uint32_t memory_pointer = HEAP_START;
void *malloc(uint32_t size);
{
memory_pointer = memory_pointer + size;
return memory_pointer - size;
}
void free(void *mem)
{
;
}
###Heap
The next method - which I prefer - is a memory heap.
The heap consists of a list of free memory areas. In the simplest possible
variety, it would look something like this:
:::c
struct area_header
{
uint32_t size;
struct free_area *next;
};
void *malloc(uint32_t size)
{
struct area_header *area = heap_list_head;
while(area)
{
if(area->size >= size)
{
remove_from_heap_list(area);
return get_memory_area(area);
}
area = area->next;
}
panic("Out of memory!");
}
void free(void *mem)
{
struct area_header area = get_area_header(mem);
insert_into_heap_list(area);
}
Here it is assumed that the free memory is already divided into smaller areas
that each start with an *area_header* structure as in the figure below. If the
memory area is allocated, the caller of _malloc_ gets a pointer to the end of
the area header. The area header thus remains untouched by the program until
the memory is freed again.
The memory could then look something like below.
Blue areas in the figure are free and red ones are allocated. The header of
each free memory area has a pointer to the next free area.
###Improvements
Some improvements can be made to this simple scheme. First, if no free area is
big enough, the heap can be increased by adding a new area with the right size
to the end. Alternatively, two free areas that are right next to each other
can be joined together to form a bigger one.
Also, it would be a good idea if an area is bigger than necessary to split it.
Finally, it's a lot easier to keep track of everything if the memory areas are
doubly linked and if allocated areas are not removed from the list but just
marked as used.
###Git
With those improvements the scheme is similar to what I've implemented in Git
commit
[8db335ce3b](https://github.com/thomasloven/os5/tree/8db335ce3bed30c8e75275c2fc96a2b697106023).
###Further improvements
Some more improvements can be made to the heap in order to increase
performance. The most common ones use different ways to search for free areas
of the correct size. For example, the free areas could be stored in an ordered
list starting with the smallest, or they could be stored in several lists
depending on their size.