有了 Buddy System 和 SLab 分配器,我们便能够去做真正的分配内存与释放内存的操作了——也即 malloc 和 free。本部分源码解析即讲解 Chcore 的内核中 kmalloc/kfree,这里的 k 表示 kernel,即专用于内核空间分配/释放的函数
直接上源码!
源码
kmalloc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| void *kmalloc(unsigned long size) { size_t real_size; void *ret; ret = _kmalloc(size, true, &real_size); return ret; }
void *_kmalloc(size_t size, bool is_record, size_t *real_size) { void *addr; int order;
if (unlikely(size == 0)) return ZERO_SIZE_PTR;
if (size <= SLAB_MAX_SIZE) { addr = alloc_in_slab(size, real_size); #if ENABLE_MEMORY_USAGE_COLLECTING == ON if(is_record && collecting_switch) { record_mem_usage(*real_size, addr); } #endif } else { if (size <= BUDDY_PAGE_SIZE) order = 0; else order = size_to_page_order(size); addr = get_pages(order); }
return addr; }
|
kfree
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void kfree(void *ptr) { _kfree(ptr, true); }
void _kfree(void *ptr, bool is_revoke_record) { struct page *page;
if (unlikely(ptr == ZERO_SIZE_PTR)) return;
page = virt_to_page(ptr); #if ENABLE_MEMORY_USAGE_COLLECTING == ON if (collecting_switch && is_revoke_record) { revoke_mem_usage(ptr); } #endif if (page && page->slab) free_in_slab(ptr); else if (page && page->pool) buddy_free_pages(page->pool, page); else kwarn("unexpected state in %s\n", __func__); }
|
解析
有了之前 Buddy System 和 SLab 提供的接口,实现这两个函数便简单多了,参数检查过后,直接用一个分支结构即可解决
kmalloc
- 参数检查
- 看需要分配的 size 大小,若小于 SLAB_MAX_SIZE 则使用 SLab 分配器的接口分配内存
- 若大于,则使用伙伴系统的接口分配内存(包装在 get_pages 函数里的,这里没有列出)
- 返回分配得到的地址指针
kfree
- 参数检查
- 根据地址拿到它所属的 page
- 看 page 的属性,如果它有 slab,则说明是 slab 里的 page,交由 slab 接口处理
- 如果它有 pool,则说明是伙伴系统的 page,交由伙伴系统接口处理