Memblock基础内容
Memblock结构体
memblock是Linux内核启动早期使用的内存管理方案,通过struct memblock结构体来记录物理内存使用情况。
memblock
|----->bottom_up
| 内存分配从高地址到低地址,还是从低地址到高地址
|----->current_limit
| 可以使用的内存的上限
|----->memory
| 记录完整的内存资源
|----->cnt
| 总的内存资源有几个region
|----->max
| 最多有几个region
|----->total_size
| 总的容量是多少
|----->regions
|----->base
| 该memory region的基地址
|----->size
| 该memory region的容量
|------>flags
| 该memory region的flag
|----->reserved
| 记录已经分配或者预留的内存资源
Memblock中有两种内存类型, memory和reserved,memory用于记录总的内存资源,reserved用于记录已经使用或者预留的内存资源。后面分析具体的代码,会对此有更清晰的认识。
添加内存:memblock_add
即向memory类型中添加内存资源,代码逻辑如下:
memblock_add
|-----> memblock_add_range
|-----> type->regions[0].base = base;
|-----> type->regions[0].size = size;
|-----> type->regions[0].flags = flags;
|-----> type->total_size = size;
| 如果该类型memory第一个region为空,则填充该region并返回
|-----> memblock_insert_region(type, idx, base, end - base, nid, flags)
| 如果该类型memory第一个region不为空,则调用该函数插入如新的region
|-----> memblock_merge_regions(type)
| 如果相邻的region可以合并,则将其合并
插入region
插入region的逻辑稍有些复杂,我这里讲插入的规则描述一下,以帮助理解代码:
- region必须从大到小排列。这里说的大小,是指region所代表的内存的起始/结束地址,也就是说,region0的结束地址,必须小于或等于region1的起始地址。
- 调用一次memblock_add,有可能将拆分成两个。
我们下面模拟几种种插入region的场景:
第一个内存块插入第一个region。
1> 第一个内存块插入region0。第二个内存块的结束地址小于第一个内存块的起始地址
1> 第一个内存块插入region1。
2> 第二个内存块插入region0。第三个内存块的开始地址大于第一个内存块的结束地址