内核刚开始启动的时候如果一步到位写一个很完善的内存管理系统是相当麻烦的。所以linux先建立了一个非常简单的临时内存管理系统bootmem,有了这个bootmem就可以做简单的内存分配/释放操作,在bootmem的基础上再做一个完善的内存管理系统就比较简单了。bootmem的本质就是位图,一个bit代表一个页框(page frame),页框分配出去就把相对应的bit置位,页框回收就把相应的bit复位。linux内核直接管理的内存是1G,所以这个位图需要2^32/4096/8=128k字节,在我另一篇文章里也提到了。
bootmem的管理结构是bootmem_data,结构如下:
typedef struct bootmem_data { unsigned long node_boot_start; //它所管理起始内存 unsigned long node_low_pfn; //它所管理的最后一个页框号 void *node_bootmem_map; //位图 unsigned long last_offset; //上次分配的页框内偏移 unsigned long last_pos; //上次分配的页框 unsigned long last_success; /* Previous allocation point. To speed * up searching */ struct list_head list; } bootmem_data_t;
分配内存和释放内存也就是对node_bootmem_map的位图操作,比较简单。值得一提的是last_pos/last_offset,如果发生如下情况:
- 第一次申请内存:申请的最后一页内存不是整页的,也就是说剩下了部分内存。
- 第二次申请内存:第一次剩下的内存大小满足这次申请,这种情况会直接使用第一次分配剩下的内存。
这样可能会造成一个问题free_bootmem释放第一次申请的内存会把第二次申请的内存也释放掉。为了避免这种情况linux内核只在初始化内存的时候使用了free_bootmem,其他地方都没用过这个函数,也就是说bootmem只申请不释放。
free_all_bootmem释放的不是已经申请的内存,而是bootmem没分配出去的内存,调用free_all_bootmem以后bootmem就把自身也释放掉了,不可用了,之后会用更高级的内存管理系统。