首頁 > 軟體

Linux Kernel是如何做到釋放僅在啟動時使用的記憶體的?

2020-06-16 17:30:35

你在哪裡

走遍千山萬水,終於找到了你。

void free_initmem(void)
{
    free_init_pages("unused kernel",
            (unsigned long)(&__init_begin),
            (unsigned long)(&__init_end));
}

啥也不說了,看這個函數名大家就知道是釋放啟動過程中使用的記憶體空間的。

只是因為在程式碼中多看了你一眼

static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;

在看記憶體管理的程式碼中,說memblock使用的記憶體在啟動後會又核心回收,繼續作為核心可以使用的記憶體。引發了我一點點的好奇心。 話說核心也是像我們貧下中農一樣,挺省吃儉用的嘛。

從程式碼上看,和普通變數定義時的差異就是這個字尾修飾,__initdata_memblock。

#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
#define __init_memblock __meminit
#define __initdata_memblock __meminitdata
#else
#define __init_memblock
#define __initdata_memblock
#endif

看來這個還得在核心設定上有所設定才能做到省吃儉用。感覺和人生一樣,有的娃出生的時候含著金鑰匙,完全不在乎那麼點記憶體;而有的就要默默執行hard模式咯。

作為窮苦的孩子,咱還是學習學習hard模式是怎麼個玩兒的哈

#define __meminitdata    __section(.meminit.data)

ok,原來就是把這個資料結構定義在了一個叫 .meminit.data的區域。
區域(section)這個高階貨大家請自行搜尋 elf section哈,因為我也不大記得了。還是不要誤導了大家。

幸福像花兒一樣

此處略過若干字,在include/asm-generic/vmlinux.lds.h檔案中,有如下定義

#if defined(CONFIG_MEMORY_HOTPLUG)
#define MEM_KEEP(sec)    *(.mem##sec)
#define MEM_DISCARD(sec)
#else
#define MEM_KEEP(sec)
#define MEM_DISCARD(sec) *(.mem##sec)
#endif

/* init and exit section handling */
#define INIT_DATA                           
    *(.init.data)                           
    MEM_DISCARD(init.data)                      
    KERNEL_CTORS()                          
    ...

#define INIT_DATA_SECTION(initsetup_align)              
    .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {       
        INIT_DATA                       
        INIT_SETUP(initsetup_align)             
        INIT_CALLS                      
        CON_INITCALL                        
        SECURITY_INITCALL                   
        INIT_RAM_FS                     
    }

我猜你已經看出點什麼來了,如果沒用猜出來那再看上述程式碼一百遍。。。
哦,忘了說了,這裡有個東西叫 “gcc連結指令碼”,大家請先自行蒐之 -_-!

踏破鐵鞋無覓處

高興得太早了,剛才一路順溜得找到了INIT_DATA_SECTION(),然後,就不知道然後了。。。

關鍵時候注釋起到了不可忽視的作用。所以說,寫程式碼註釋很重要。

 * SECTIONS
 * {
 *  . = START;
 *  __init_begin = .;
 *  HEAD_TEXT_SECTION
 *  INIT_TEXT_SECTION(PAGE_SIZE)
 *  INIT_DATA_SECTION(...)
 *  PERCPU_SECTION(CACHELINE_SIZE)
 *  __init_end = .;
 *
 * ...
 * }

原來啟動階段可以釋放的記憶體不僅僅是記憶體初始化相關的部分,還包括了其他好多東西。嗯,又那麼深入了一點點~

好了,你看這裡和最開始的free_initmem()有沒有點眼熟呢?
我相信你會發現的:)

好了,今天就到這裡,希望對你有幫助~

本文永久更新連結地址http://www.linuxidc.com/Linux/2016-10/135907.htm


IT145.com E-mail:sddin#qq.com