boot memory allocator——自举内存分配器(四:内存释放)
2012-08-16 22:55
309 查看
在bootmem阶段,内核提供了free_bootmem函数来释放内存。它需要两个参数:需要释放的内存区的起始地址和长度。不出意外,NUMA系统上等价函数的名称为free_bootmem_node,它需要一个额外的参数来指定结点。
两个版本都将其工作委托给_free_bootmem_core,只能释放整页,因为bootmem分配器没有保存有关页划分的任何信息。内核使用_free_bootmem_core首先计算完全包含在该内存区中、将被释放的页。只是部分包含在内存区中的页将忽略。位图中对应的项设置为0,完成页的释放。对_free_bootmem_core的分析如下:
void __init free_bootmem(unsigned long addr, unsigned long size) { free_bootmem_core(NODE_DATA(0)->bdata, addr, size); }
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, unsigned long size) { free_bootmem_core(pgdat->bdata, physaddr, size); }
两个版本都将其工作委托给_free_bootmem_core,只能释放整页,因为bootmem分配器没有保存有关页划分的任何信息。内核使用_free_bootmem_core首先计算完全包含在该内存区中、将被释放的页。只是部分包含在内存区中的页将忽略。位图中对应的项设置为0,完成页的释放。对_free_bootmem_core的分析如下:
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,unsigned long size) { unsigned long sidx, eidx; unsigned long i; /* * round down end of usable mem, partially free pages are * considered reserved. */ BUG_ON(!size);//如果释放空内存,系统崩溃 BUG_ON(PFN_DOWN(addr + size) > bdata->node_low_pfn);//需要释放的空间的最后位置的绝对页号不能释放超过本节点范围内的内存空间,否则系统崩溃 if (addr < bdata->last_success) bdata->last_success = addr;//如果addr<bdata->last_success,那么作了这一次空间释放以后,就需要更新该结点中上一次成功分配内存的位置 /* * Round up the beginning of the address. */ sidx = PFN_UP(addr) - PFN_DOWN(bdata->node_boot_start);//此处使用PFN_UP(addr)是为了计算开始地址的全新页,假设addr是在0~4kb的地址范围的话,其实真正在0号页的位置,但是如果通过上面的运算,求出来的就是1号页的位置。为什么这样做呢?因为如果起始地址不是按页对齐的,如果直接释放,就会把前面不属于这个内存node的空间也释放了,而后面为什么是PFN_DOWN(bdata->node_boot_start)而不是PFN_UP(bdata->node_boot_start),因为如果后面是PFN_UP(bdata->node_boot_start)的话,就会把当前内存结点最后一页中的后面那一部分不属于该内存结点的空间给释放掉了。这样就计算出了新页和原来的起始地址所在页的偏移页数。 eidx = PFN_DOWN(addr + size - bdata->node_boot_start);//计算出要释放空间的结束位置相对于该内存节点的起始位置的偏移页数 for (i = sidx; i < eidx; i++) {//这里是对要释放的页对应的页帧位码表的位清零 if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map)))//如果发现页帧位码表的那些位已经为0的话,系统就崩溃了 BUG(); } }该过程隐藏了一些风险,如果也包含在两个不同的内存区,那么连续释放这些内存区,却无法释放该页。包含页的前一半和后一半的内存区在间隔一段时间后分别被释放,分配器无法了解到该页是否不再使用,因此也无法释放。该页的状态就一直保持为“使用中”,尽管事实上不是这样。尽管如此,由于free_bootmem很少使用,这也不是大问题。系统初始化期间分配的大多数内存区都用于基本的数据结构,在内核运行的所有时间都需要使用,因此无需释放。
相关文章推荐
- boot memory allocator——自举内存分配器(三:内存分配)
- boot memory allocator——自举内存分配器(二:在IA-32系统下的初始化)
- boot memory allocator——自举内存分配器(一:基本介绍)
- boot memory allocator——自举内存分配器(五:停用bootmem)
- 内核内存分配器(Kernel Memory Allocator, KMA)
- 14.6.4 Configuring the Memory Allocator for InnoDB 配置InnoDB 内存分配器
- 14.6.4 Configuring the Memory Allocator for InnoDB 配置InnoDB 内存分配器
- 实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
- [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
- C++中的allocator类(内存分配器)
- C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
- STL内存分配器:allocator
- 内核早期内存分配器 - memblock与bootmem
- uboot 的内存命令使用: mw (修改) md (显示),u-boot 内存 memory
- php Allocator Jemalloc TCMalloc那个内存分配器比较好?
- [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
- [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
- Boost.Interprocess使用手册翻译之八:分配器,容器和内存分配算法(Allocators, containers and memory allocation algorithms)
- uboot 的内存命令使用: mw (修改) md (显示),u-boot 内存 memory
- 内核的bootmem内存分配器【转】