Memory Allocation: Difference between revisions

brk and sbrk are uninterfaces, removed by decree from the ministry of truth
[unchecked revision][unchecked revision]
(brk and sbrk are uninterfaces, removed by decree from the ministry of truth)
Line 59:
It's not always desirable or practical to write your own memory allocator. Writing an efficient memory allocator can be an entire project in itself and fortunately it's extremely easy to port an existing memory allocator to your OS (to run in either kernel or user space). The advantages of using an existing memory allocator are; porting one is much faster than writing your own especially when you want to focus on other areas of your OS, it is likely to be well-tested so you do not have to debug the memory allocator, it takes a minimal amount of work to port it, and finally, someone else has down the hard work to make it fast, scalable, stable, etc.
 
Porting a memory allocator is fairly simple to do. Most of them are no more than one source and/or header file. The functionality you must hook is for allocating and freeing pages to your program, so the memory allocator has memory to work with. Depending on the allocator you're using, there are two different pairs of hooks you will need to implement. For allocators that use the old UNIX way of requesting more program memory from the kernel you must hook/implement:
 
There are also an alternativea pair of hooks that some memory allocators use which allow the allocator to request memory from the kernel in terms of 'pages'. These memory allocators will have a constant stored somewhere in the source on how many large a page is (e.g. '#define PAGE_SIZE 4096' for 4KB pages) so the allocator knows how many pages to request at a time. With these allocators you must hook/implement:
*void *sbrk(size_t amount) - Increments the end of program's memory to by 'amount' bytes and returns a pointer to the beginning of the incremented amount. It doesn't matter if the amount requested doesn't line up with your page sizes or not, because you simply allocate enough pages to cover the amount requested, and then you subtract any leftover memory from 'amount' next time sbrk is called. Calling sbrk(0) returns a pointer to the end of the program's memory.
*int brk(void *end_data_segment) - Shrinks the programs memory to 'end_data_segment'. It releases all of the memory after 'end_data_segment' back to the kernel. Just like with sbrk, 'end_data_segment' does not have to line up with your page sizes.
 
*void free_page*alloc_page(void *start, intsize_t pages) - FreesAllocates 'pages' consecutive pages in virtual memory fromand 'start'returns backa pointer to the kernelbeginning of the group.
There are also an alternative pair of hooks that some memory allocators use which allow the allocator to request memory from the kernel in terms of 'pages'. These memory allocators will have a constant stored somewhere in the source on how many large a page is (e.g. '#define PAGE_SIZE 4096' for 4KB pages) so the allocator knows how many pages to request at a time. With these allocators you must hook/implement:
*void free_page(void *start, size_t pages) - Frees 'pages' consecutive pages in virtual memory from 'start' back to the kernel.
 
*void *alloc_page(int pages) - Allocates 'pages' consecutive pages in virtual memory and returns a pointer to the beginning of the group. Some allocators may allow you to return NULL or a magic value to indicate that the system or the program is out of memory, however do not assume you can return NULL/0 when failing as many allocators will actually think 0x0000 0000 is a valid address and try to allocate memory there.
*void free_page(void *start, int pages) - Frees 'pages' consecutive pages in virtual memory from 'start' back to the kernel.
 
In addition, some memory allocators will require you to hook locking functionality to ensure critical sections of the memory allocator aren't executed simultaneously by multiple threads. Typically the functions will appear like;
Anonymous user