目录
1. reserved-memory缩减内存
2. 为什么要通过2段512GB预留内存实现该缩减呢?
3. reserved-momery中的no-map属性
4. 预留的的内存是否会被统计到系统MemTotal中?
本文是解决具体的一些思考总结,和Linux内核的reserved-memory机制相关。
参考代码:Linux-6.10
1. reserved-memory缩减内存
实际开发过程有需求验小内存产品时系统性能情况,为节省成本直接将大内存产品的内存进行软件缩减成小内然后进行性能验证。
例如有8GB内存产品需要缩减为7GB内存,通过Linux内核的reserved-memory机制实现该缩减需求,具体修改如下。通过预留2段512GB内存的reserved-memory内存,来达到缩减1GB内存的目的。对于此预留机制实现的缩减方案会有一些疑问,随后就相关疑问进行调查解答。
reserved-memory {#address-cells = <2>;#size-cells = <2>;ranges;removed-memory1:removed_memory_region1 {alloc-renges=<0x0 0x00000000 0xffffffff 0xffffffff>;size= <0x0 0x20000000>; //512MBytesno-map;};removed-memory2:removed_memory_region2 {alloc-renges=<0x0 0x00000000 0xffffffff 0xffffffff>;size= <0x0 0x20000000>; //512MBytesno-map;};}
2. 为什么要通过2段512GB预留内存实现该缩减呢?
答案是可以是1段1GB或者多个段合成1GB遗留内存,但是要确保每段的预留内存可以预留成功。
reserved-momory是遍历memblock.memory域中的可以内存,从可用内存空间中划分一段符合预留内存要求的内存空间放到memblock.reserved区域,又因为memblock.memory域中的内存已经被划分为多个段,如果要预留1GB空间的内存时任意一段内存空间可能小于1GB,则需要将预留的内存空间划分为多个小端内存就行预留。如上将1GB的预留内存空间划分为2个512MB,就是为了确保预留内存的成功预留。所以预留内存时,无论划分成了几段预留要需要保证每一段度都预留成功,为了保证预留成功尽可能的将大内存划分为多个小段内存进行预留。
具体逻辑可以解析__reserved_mem_alloc_in_range()函数。
3. reserved-momery中的no-map属性
预留的内存如果不想被系统使用,则需要添加no-map属性。该属性保证预留的内存不会在系统内存映射时被映射到虚拟空间。对应代码逻辑:
文件路径:arch/arm64/mm/mmu.cstatic void __init map_mem(pgd_t *pgdp)
{……//遍历memblock.memory内存region,对符合要求的内存region进行映射for_each_mem_range(i, &start, &end) {if (start >= end)break;//对符合要求的memblock.memory内存进行映射__map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL), flags);}……
}
for_each_mem_range定义如下,该宏目的在于变量memblock.memory中的所有内存域,遍历时会调用到should_skip_region()函数,该函数会跳过具有MEMBLOCK_NOMAP标识的内存块,故具有MEMBLOCK_NOMAP标识的内存块不会被进行内存映射。
#define for_each_mem_range(i, p_start, p_end) \
__for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE, \MEMBLOCK_HOTPLUG | MEMBLOCK_DRIVER_MANAGED, \p_start, p_end, NULL)
4. 预留的的内存是否会被统计到系统MemTotal中?
答案是否定的,具有no-map属性reserved-memory预留内存是不是被统计到mem total中。 /poc/meminfo中的MemTotal值来自系统变量_totalram_pages,则从_totalram_pages赋值逻辑可以确认预留内存是否被统计到MemTotal。系统在进行__totalram_pages统计时,因为调用到should_skip_region()函数,具有no-map属性的page会被排除统计。所以给方式预留的内存不会被统计到系统的memtotal中。
如下函数是给_totalram_pages赋值的部分逻辑:
void __init memblock_free_all(void)
{unsigned long pages;free_unused_memmap();reset_all_zones_managed_pages();//统计系统free状态的page数量pages = free_low_memory_core_early();//将free的page数量添加给_totalram_pagestotalram_pages_add(pages);
}
static unsigned long __init free_low_memory_core_early(void){unsigned long count = 0;phys_addr_t start, end;u64 i;memblock_clear_hotplug(0, -1);memmap_init_reserved_pages();//遍历memblock.memory 和 memblock.reserved两个域内存,遍历时会调用should_skip_region()函//数跳过具有MEMBLOCK_NOMAP属性的内存区域,故具有MEMBLOCK_NOMAP标识的内存区域//不会被统计到。所以 memblock.momory中具有MEMBLOCK_NOMAP标识的内存区域不会被//统计到MemTotal中。另因为有遍历memblock.reserved内存区域,故memblock.reserved中//不符合should_skip_region()函数的要求内存区域也可能被统计到MemTotal中for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, NULL)count += __free_memory_core(start, end);return count;
}