在lk中通过我们一般通过malloc来申请内存
void *malloc(size_t size)
{
return heap_alloc(size, 0);
}
malloc 直接调用heap_alloc 来申请。
lk_main函数中通过调用heap_init来初始由于malloc申请的heap
void heap_init(void)
{
LTRACE_ENTRY;
// set the heap range
theheap.base = (void *)HEAP_START;
theheap.len = HEAP_LEN;
// initialize the free list
list_initialize(&theheap.free_list);
// create an initial free chunk
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));
}
可以看到这个函数一开始就要设置heap 需要管理的memory的start 和 size
这两个宏定义如下:
#define HEAP_START ((unsigned long)&_end)
#define HEAP_LEN ((size_t)&_end_of_ram - (size_t)&_end)
_end 和 _end_of_ram 又是在下面的文件中定义的
system-onesegment.ld
__data_end = .;
/* unintialized data (in same segment as writable data) */
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss .bss.*) }
. = ALIGN(4);
_end = .;
. = %MEMBASE% + %MEMSIZE%;
_end_of_ram = .;
可以看到需要用户自己定义MEMBASE 和 MEMSIZE 变量
我们继续看heap_init
会调用下面的函数初始free list
// initialize the free list
list_initialize(&theheap.free_list);
可见这个时候free list是空的
static inline void list_initialize(struct list_node *list)
{
list->prev = list->next = list;
}
继续看是如何插入chunk的
// create an initial free chunk
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));
其中heap_create_free_chunk 的实现如下,
struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len)
{
DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary
struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr;
chunk->len = len;
return chunk;
}
可知lk中是用chunk 来管理memory的,刚开始的时候只有一个很大的chunk
heap_insert_free_chunk的实现如下:
static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk)
{
#if DEBUGLEVEL > INFO
vaddr_t chunk_end = (vaddr_t)chunk + chunk->len;
#endif
// dprintf("%s: chunk ptr %p, size 0x%lx, chunk_end 0x%x\n", __FUNCTION__, chunk, chunk->len, chunk_end);
struct free_heap_chunk *next_chunk;
struct free_heap_chunk *last_chunk;
// walk through the list, finding the node to insert before
list_for_every_entry(&theheap.free_list, next_chunk, struct free_heap_chunk, node) {
if (chunk < next_chunk) {
DEBUG_ASSERT(chunk_end <= (vaddr_t)next_chunk);
list_add_before(&next_chunk->node, &chunk->node);
goto try_merge;
}
}
// walked off the end of the list, add it at the tail
list_add_tail(&theheap.free_list, &chunk->node);
// try to merge with the previous chunk
try_merge:
last_chunk = list_prev_type(&theheap.free_list, &chunk->node, struct free_heap_chunk, node);
if (last_chunk) {
if ((vaddr_t)last_chunk + last_chunk->len == (vaddr_t)chunk) {
// easy, just extend the previous chunk
last_chunk->len += chunk->len;
// remove ourself from the list
list_delete(&chunk->node);
// set the chunk pointer to the newly extended chunk, in case
// it needs to merge with the next chunk below
chunk = last_chunk;
}
}
// try to merge with the next chunk
if (next_chunk) {
if ((vaddr_t)chunk + chunk->len == (vaddr_t)next_chunk) {
// extend our chunk
chunk->len += next_chunk->len;
// remove them from the list
list_delete(&next_chunk->node);
}
}
return chunk;
}
这个函数首先会根据chunk的地址,来将chunk插入到free list的位置中,这里也可以知道free list 中的chunk 是按地址排序的
这个函数后面的部分会试图对已存在的chunk进行合并,类似kernel中的buddy system
前面讲过malloc 直接调用heap_alloc来申请内存
void *heap_alloc(size_t size, unsigned int alignment)
{
void *ptr;
LTRACEF("size %zd, align %d\n", size, alignment);
// alignment must be power of 2
if (alignment & (alignment - 1))
return NULL;
// we always put a size field + base pointer + magic in front of the allocation
size += sizeof(struct alloc_struct_begin);
// make sure we allocate at least the size of a struct free_heap_chunk so that
// when we free it, we can create a struct free_heap_chunk struct and stick it
// in the spot
if (size < sizeof(struct free_heap_chunk))
size = sizeof(struct free_heap_chunk);
// round up size to a multiple of native pointer size
size = ROUNDUP(size, sizeof(void *));
// deal with nonzero alignments
if (alignment > 0) {
if (alignment < 16)
alignment = 16;
// add alignment for worst case fit
size += alignment;
}
// critical section
enter_critical_section();
// walk through the list
ptr = NULL;
struct free_heap_chunk *chunk;
list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) {
DEBUG_ASSERT((chunk->len % sizeof(void *)) == 0); // len should always be a multiple of pointer size
// is it big enough to service our allocation?
if (chunk->len >= size) {
ptr = chunk;
// remove it from the list
struct list_node *next_node = list_next(&theheap.free_list, &chunk->node);
list_delete(&chunk->node);
if (chunk->len > size + sizeof(struct free_heap_chunk)) {
// there's enough space in this chunk to create a new one after the allocation
struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size);
// truncate this chunk
chunk->len -= chunk->len - size;
// add the new one where chunk used to be
if (next_node)
list_add_before(next_node, &newchunk->node);
else
list_add_tail(&theheap.free_list, &newchunk->node);
}
// the allocated size is actually the length of this chunk, not the size requested
DEBUG_ASSERT(chunk->len >= size);
size = chunk->len;
ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin));
// align the output if requested
if (alignment > 0) {
ptr = (void *)ROUNDUP((addr_t)ptr, alignment);
}
struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr;
as--;
as->magic = HEAP_MAGIC;
as->ptr = (void *)chunk;
as->size = size;
break;
}
}
LTRACEF("returning ptr %p\n", ptr);
// heap_dump();
exit_critical_section();
return ptr;
}
这个函数前一部分size,例如需要在size基础上加上alloc_struct_begin的size,用于管理chunk
size 要至少4byte对其等
后办法通过list_for_every_entry 遍历free list 找到size满足用户申请的size后,将chunk的起始地址返回
给用户.
void *malloc(size_t size)
{
return heap_alloc(size, 0);
}
malloc 直接调用heap_alloc 来申请。
lk_main函数中通过调用heap_init来初始由于malloc申请的heap
void heap_init(void)
{
LTRACE_ENTRY;
// set the heap range
theheap.base = (void *)HEAP_START;
theheap.len = HEAP_LEN;
// initialize the free list
list_initialize(&theheap.free_list);
// create an initial free chunk
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));
}
可以看到这个函数一开始就要设置heap 需要管理的memory的start 和 size
这两个宏定义如下:
#define HEAP_START ((unsigned long)&_end)
#define HEAP_LEN ((size_t)&_end_of_ram - (size_t)&_end)
_end 和 _end_of_ram 又是在下面的文件中定义的
system-onesegment.ld
__data_end = .;
/* unintialized data (in same segment as writable data) */
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss .bss.*) }
. = ALIGN(4);
_end = .;
. = %MEMBASE% + %MEMSIZE%;
_end_of_ram = .;
可以看到需要用户自己定义MEMBASE 和 MEMSIZE 变量
我们继续看heap_init
会调用下面的函数初始free list
// initialize the free list
list_initialize(&theheap.free_list);
可见这个时候free list是空的
static inline void list_initialize(struct list_node *list)
{
list->prev = list->next = list;
}
继续看是如何插入chunk的
// create an initial free chunk
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));
其中heap_create_free_chunk 的实现如下,
struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len)
{
DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary
struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr;
chunk->len = len;
return chunk;
}
可知lk中是用chunk 来管理memory的,刚开始的时候只有一个很大的chunk
heap_insert_free_chunk的实现如下:
static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk)
{
#if DEBUGLEVEL > INFO
vaddr_t chunk_end = (vaddr_t)chunk + chunk->len;
#endif
// dprintf("%s: chunk ptr %p, size 0x%lx, chunk_end 0x%x\n", __FUNCTION__, chunk, chunk->len, chunk_end);
struct free_heap_chunk *next_chunk;
struct free_heap_chunk *last_chunk;
// walk through the list, finding the node to insert before
list_for_every_entry(&theheap.free_list, next_chunk, struct free_heap_chunk, node) {
if (chunk < next_chunk) {
DEBUG_ASSERT(chunk_end <= (vaddr_t)next_chunk);
list_add_before(&next_chunk->node, &chunk->node);
goto try_merge;
}
}
// walked off the end of the list, add it at the tail
list_add_tail(&theheap.free_list, &chunk->node);
// try to merge with the previous chunk
try_merge:
last_chunk = list_prev_type(&theheap.free_list, &chunk->node, struct free_heap_chunk, node);
if (last_chunk) {
if ((vaddr_t)last_chunk + last_chunk->len == (vaddr_t)chunk) {
// easy, just extend the previous chunk
last_chunk->len += chunk->len;
// remove ourself from the list
list_delete(&chunk->node);
// set the chunk pointer to the newly extended chunk, in case
// it needs to merge with the next chunk below
chunk = last_chunk;
}
}
// try to merge with the next chunk
if (next_chunk) {
if ((vaddr_t)chunk + chunk->len == (vaddr_t)next_chunk) {
// extend our chunk
chunk->len += next_chunk->len;
// remove them from the list
list_delete(&next_chunk->node);
}
}
return chunk;
}
这个函数首先会根据chunk的地址,来将chunk插入到free list的位置中,这里也可以知道free list 中的chunk 是按地址排序的
这个函数后面的部分会试图对已存在的chunk进行合并,类似kernel中的buddy system
前面讲过malloc 直接调用heap_alloc来申请内存
void *heap_alloc(size_t size, unsigned int alignment)
{
void *ptr;
LTRACEF("size %zd, align %d\n", size, alignment);
// alignment must be power of 2
if (alignment & (alignment - 1))
return NULL;
// we always put a size field + base pointer + magic in front of the allocation
size += sizeof(struct alloc_struct_begin);
// make sure we allocate at least the size of a struct free_heap_chunk so that
// when we free it, we can create a struct free_heap_chunk struct and stick it
// in the spot
if (size < sizeof(struct free_heap_chunk))
size = sizeof(struct free_heap_chunk);
// round up size to a multiple of native pointer size
size = ROUNDUP(size, sizeof(void *));
// deal with nonzero alignments
if (alignment > 0) {
if (alignment < 16)
alignment = 16;
// add alignment for worst case fit
size += alignment;
}
// critical section
enter_critical_section();
// walk through the list
ptr = NULL;
struct free_heap_chunk *chunk;
list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) {
DEBUG_ASSERT((chunk->len % sizeof(void *)) == 0); // len should always be a multiple of pointer size
// is it big enough to service our allocation?
if (chunk->len >= size) {
ptr = chunk;
// remove it from the list
struct list_node *next_node = list_next(&theheap.free_list, &chunk->node);
list_delete(&chunk->node);
if (chunk->len > size + sizeof(struct free_heap_chunk)) {
// there's enough space in this chunk to create a new one after the allocation
struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size);
// truncate this chunk
chunk->len -= chunk->len - size;
// add the new one where chunk used to be
if (next_node)
list_add_before(next_node, &newchunk->node);
else
list_add_tail(&theheap.free_list, &newchunk->node);
}
// the allocated size is actually the length of this chunk, not the size requested
DEBUG_ASSERT(chunk->len >= size);
size = chunk->len;
ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin));
// align the output if requested
if (alignment > 0) {
ptr = (void *)ROUNDUP((addr_t)ptr, alignment);
}
struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr;
as--;
as->magic = HEAP_MAGIC;
as->ptr = (void *)chunk;
as->size = size;
break;
}
}
LTRACEF("returning ptr %p\n", ptr);
// heap_dump();
exit_critical_section();
return ptr;
}
这个函数前一部分size,例如需要在size基础上加上alloc_struct_begin的size,用于管理chunk
size 要至少4byte对其等
后办法通过list_for_every_entry 遍历free list 找到size满足用户申请的size后,将chunk的起始地址返回
给用户.