作業系統核心

kmalloc 與 vmalloc

/ KAY-mal-ock / VEE-mal-ock /

在核心裡,你不能呼叫使用者程式所用的那個普通 malloc()——它住在 C 函式庫裡,那是使用者空間的程式碼。核心有它自己的配置器來臨時抓取記憶體,你最先遇到的兩個是 kmalloc 與 vmalloc。它們都給你一塊記憶體,但對那塊記憶體在實體 RAM 中如何佈局,做出不同的承諾,而這個差別決定何時用哪個。

kmalloc 回傳實體連續的記憶體:你拿到的位元組佔據真實 RAM 中相鄰的位置,而不只是相鄰的虛擬位址。這種連續性對某些東西至關重要,例如交給做直接記憶體存取硬體的緩衝區,因為裝置看到的是實體位址,且往往需要一段不間斷的連續區。代價是當記憶體碎裂時,要找一大塊實體連續的區塊可能失敗,所以 kmalloc 最適合中小型的配置。vmalloc 則回傳僅在虛擬位址空間中連續的記憶體:幕後核心可能把實體上分散的分頁縫合起來,映射成看似一塊連續的區域。這即便在碎裂下對大型配置也能成功(它不需要一大段連續的實體區),但設定起來較慢、用掉額外的分頁表項,而且其結果交給一個期望實體連續的裝置是不安全的。

務實的經驗法則:預設用 kmalloc——它較快且連續——尤其當硬體會碰觸那塊記憶體時;當你需要一個大型緩衝區、且只有核心自己會用它,虛擬連續就夠了,這時改用 vmalloc。也請注意,小型 kmalloc 請求其實是由 slab/SLUB 配置器在底下切割來自夥伴分頁配置器的分頁來服務的,所以這些名字是疊在較低層機制之上,而非取代它。而在中斷上下文裡,你必須傳像 GFP_ATOMIC 這樣的旗標,使配置絕不睡眠——在那裡做一個普通會睡眠的配置,正是那個經典的上下文臭蟲。

char *buf = kmalloc(256, GFP_KERNEL); // 小、實體連續——適合 DMA。char *big = vmalloc(8 * 1024 * 1024); // 8 MiB、虛擬連續、實體分頁分散——僅供核心、不可給裝置。

kmalloc = 小、實體連續(可安全用於硬體 DMA);vmalloc = 大、僅虛擬連續(僅供核心)。

vmalloc 的記憶體只在虛擬位址上連續——它的實體分頁可能分散,所以絕不要把 vmalloc 緩衝區交給一個期望實體連續以做 DMA 的裝置。此外,在中斷上下文裡你必須用 GFP_ATOMIC;在那裡做預設會睡眠的配置可能讓機器死結。

又称
kmalloc()vmalloc()kernel memory allocation核心記憶體配置