目錄
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;
}