作者:朱涵俊
链接:https://zhuanlan.zhihu.com/p/140274586
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
内核在启动的过程中需要不断申请内存,这些内存申请之后一般就不需要释放。频繁的申请释放会导致内存碎片,性能下降。因此内核堆kheap管理的原则是申请一次,终身使用。堆内存分为2类,一是小内存,而是页对齐的内存。因为有的内核对象需要页对齐,比如页表。
kernel/kheap.c
- //由于只申请不释放,不会有很多内存块。主要是BIOS,内核数据等引起的。
- #define MAX_HEAP_HOLE 10
- #define MAX_SMALL_HOLE 100
- #if 1
- #define DEBUG_PRINT printk
- #else
- #define DEBUG_PRINT inline_printk
- #endif
-
- struct kheap_t;
- struct kheap_t {
- ulong addr;
- ulong size;
- ulong orgin_size;
- struct kheap_t *pnext;
- };
- static struct kheap_t *pfree4k;
- static struct kheap_t *phead4k;
- static struct kheap_t heap_holes[MAX_HEAP_HOLE];
- static struct kheap_t heap_small_holes[MAX_SMALL_HOLE];
- __thread static spinlock_t spin_4k;
- __thread static spinlock_t spin_small;
- static struct kheap_t *pfree_small;
- static struct kheap_t *phead_small;
- void init_kheap()
- {
- for (int i = 0; i < MAX_HEAP_HOLE - 1; i++) {
- heap_holes[i].pnext = &heap_holes[i + 1];
- }
- heap_holes[MAX_HEAP_HOLE - 1].pnext = 0;
- pfree4k = heap_holes;
- phead4k = 0;
- init_spinlock(&spin_4k);
-
- for (int i = 0; i < MAX_SMALL_HOLE - 1; i++) {
- heap_small_holes[i].pnext = &heap_small_holes[i + 1];
- }
- heap_small_holes[MAX_SMALL_HOLE - 1].pnext = 0;
- pfree_small = heap_small_holes;
- phead_small = 0;
- init_spinlock(&spin_small);
-
- }
- void free_kheap_4k(ulong addr, ulong size)
- {
- struct kheap_t *p;
- struct kheap_t *ph;
-
- ASSERT((addr & 0xfff) == 0 && (size & 0xfff) == 0); //4k aligned
-
- p = pfree4k;
- if (!p) {
- panic("MAX_HEAP_HOLE too small!\n");
- }
- spin_lock(&spin_4k);
- pfree4k = pfree4k->pnext;
- p->addr = addr;
- p->orgin_size = size;
- p->size = size;
- //sort by addr asc,early init can only use low kheap
- if (!phead4k || phead4k->addr > p->addr) {
- p->pnext = phead4k;
- phead4k = p;
- spin_unlock(&spin_4k);
- return;
- }
-
- ph = phead4k;
- while (ph->pnext && ph->pnext->addr < p->addr) {
- ph = ph->pnext;
- }
- p->pnext = ph->pnext;
- ph->pnext = p;