Linux 記憶體管理之highmem簡介

2021-09-30 09:41:03 字數 3108 閱讀 2982

一、linux核心位址空間

一般來說linux 核心按照 3:1 的比率來劃分虛擬記憶體(x86等):3 gb 的虛擬記憶體用於使用者空間,1gb 的記憶體用於核心空間。當然有些體系結構如mips使用2:2 的比率來劃分虛擬記憶體:2 gb 的虛擬記憶體用於使用者空間,2 gb 的記憶體用於核心空間,另外像arm架構的虛擬空間是可配置(1:3、2:2、3:1)。核心線性位址空間用於為核心的執行提供最基本的支援,也是作業系統賴以存在的基礎。所謂核心線性位址空間就是說核心態下虛擬位址與實體地址是線性關係,兩者相差乙個固定偏差,計算公式為va(虛擬位址)=pa(實體地址)+page_offset。

二、什麼是高階記憶體

以x86為例linux中核心使用3g-4g的線性位址空間,也就是說總共只有1g的位址空間可以用來對映實體地址空間。但是,如果記憶體大於1g的情況下核心態線性位址就不夠用了。為此核心引入了乙個高階記憶體的概念,把1g的線性位址空間劃分為兩部分:小於896m實體地址空間的稱之為低端記憶體,這部分記憶體的實體地址和3g開始的線性位址是一一對應對映的,也就是說核心使用的線性位址空間(va)3g--(3g+896m)和實體地址空間(pa)0-896m一一對應,page_offset=0xc0000000;剩下的128m的線性空間用來對映剩下的大於896m的實體地址空間,這也就是我們通常說的高階記憶體區,這部分空間需要mmu通過tlb表來建立動態的對映關係。

三、高階記憶體對映

高階記憶體對映有三種方式:

1、  臨時對映空間

固定對映空間是核心線性空間中的一組保留虛擬頁面空間,位於核心線性位址的末尾即最高位址部分。其位址編譯時確定,用於特定用途(如vsyscall系統呼叫,mips的cache著色)。由列舉型別  fixed_addresses決定,核心在fixaddr_start 到 fixaddr_top 之間

在這個空間中,有一部分用於高階記憶體的臨時對映。這塊空間具有如下特點: 每個 cpu 占用一塊空間;可以用在中斷處理函式和可延遲函式的內部,從不阻塞,禁止核心搶占;在每個 cpu 占用的那塊空間中,又分為多個小空間,每個小空間大小是 1 個 page,每個小空間用於乙個目的,這些目的定義在 kmap_types.h 中的 km_type 中。

當要進行一次臨時對映的時候,需要指定對映的目的,根據對映目的,可以找到對應的小空間,然後把這個空間的位址作為對映位址。這意味著一次臨時對映會導致以前的對映被覆蓋。

介面函式:kmap_atomic/kunmap_atomic。 使用從fix_kmap_begin到fix_kmap_end之間的物理頁

2、  長久對映空間

長久對映位址空間是預留的線性位址空間。訪問高記憶體的一種手段。使用方式是先通過alloc_page() 獲得了高階記憶體對應的 page,然後核心從專門為此留出的線性空間分配乙個虛擬位址,在 pkmap_base 到 fixaddr_start 之間。

介面函式:void*kmap(struct *page)、 void kumap(struct *page)

該介面函式在高/低記憶體都能使用,可以睡眠,數量有限。對於不使用的的 page,及應該時從這個空間釋放掉(也就是解除對映關係)。

#definepkmap_base ((fixaddr_boot_start - page_size * (last_pkmap + 1)) & pmd_mask)

#definelast_pkmap 1024

3、非連續對映位址空間

非連續對映位址空間適用於為不頻繁申請釋放記憶體的情況,這樣不會頻繁的修改核心頁表。總的來說,核心主要在以下情況使用非連續對映位址空間:對映裝置的i/o空間;為核心模組分配空間;為交換分割槽分配空間

每個非連續記憶體區都對應乙個型別為vm_struct 的描述符,通過next欄位,這些描述符被插入到乙個vmlist鍊錶中。

這種方式下高階記憶體使用簡單,因為通過vmalloc() ,在」核心動態對映空間「申請記憶體的時候,就可能從高階記憶體獲得頁面(參看 vmalloc 的實現),因此說高階記憶體有可能對映到」核心動態對映空間「中。

介面函式:vmalloc(vfree):物理記憶體(呼叫alloc_page)和線性位址同時申請,物理記憶體是 __gfp_highmem型別(分配順序是high, normal , dma )(可見vmalloc不僅僅可以對映highmem頁框,它的主要目的是為了將零散的,不連續的頁框拼湊成連續的核心邏輯位址空間... );

vmap(vumap):vmalloc的簡化版;

ioremap(iounmap):分配i/o對映空間;



四、mips的高階記憶體

mips的highmem管理可參見其官方簡介:

在mips32 cpu中不經過mmu轉換的記憶體視窗只有kseg0和kseg1 的512mb的大小,而且這兩個記憶體視窗對映到同一得0~512m的實體地址空間。其餘的3g虛擬位址空間需要經過mmu轉換成實體地址,這個轉換規則是由cpu 廠商實現的。換句話說,在mips32 cpu下面訪問高於512m的實體地址空間,必須通過mmu位址轉換。即按va=pa+page_offset公式對映的空間最大只有512m,其中page_offset=0x80000000,而在linux中mips32只使用其中的256mb。

mips在higmem使用過程中需要注意兩個問題:一是要考慮由higmem帶來的整個系統效能和穩定性間的平衡,二是highmem不支援cache aliases。

五、總結

高階記憶體含義為:線性位址空間 page_offset+highstart至4g的最後線性位址 <==對映==> highstart以上的物理頁框,非直接對映。有3種方法:非連續記憶體區對映,永久核心對映,臨時核心對映(固定對映)。

使用者空間當然可以使用高階記憶體,而且是正常的使用,核心在分配那些不經常使用的記憶體時,都用高階記憶體空間(如果有),所謂不經常使用是相對來說的,比如核心的一些資料結構就屬於經常使用的,而使用者的一些資料就屬於不經常使用的。

使用者在啟動乙個應用程式時,是需要記憶體的,而每個應用程式都有3g的線性位址,給這些位址對映頁表時就可以直接使用高階記憶體。

總之,核心的高階線性位址是為了訪問核心固定對映以外的記憶體資源。實際上高階記憶體是針對核心一段特殊的線性空間提出的概念,和實際的物理記憶體是兩碼事。程序在使用記憶體時,觸發缺頁異常,具體將哪些物理頁對映給使用者程序是核心考慮的事情。在使用者空間中沒有高階記憶體這個概念。

注:1、本文中本文中虛擬位址和線性位址沒做細緻區分,可認為是乙個概念。

2、關於highmem的**分析可參見《關於高階記憶體的一些筆記

》一文:

linux記憶體管理 之 DMA

1 dma 直接記憶體訪問 用於在主存貯器和裝置記憶體之間的大量資料的交換,無須cpu參與,可以提高系統效率。2 核心中的dma層 3 dma的位址 dma addr t 4 dma set mask 查詢dma定址範圍 5 dma對映 a 一致性dma對映 static inline void d...

Linux記憶體管理

本文首先介紹一下linux記憶體管理方式,著重說明一下使用者空間的記憶體管理,包括linux虛擬對映以及glibc中malloc的實現 然後簡要介紹單程序多執行緒的記憶體管理方式,主要涉及各執行緒堆疊空間的分配 linux 採用兩級保護機制,隔離核心空間和使用者程式空間,使使用者程式無法直接訪問核心...

Linux記憶體管理

本文首先介紹一下linux記憶體管理方式,著重說明一下使用者空間的記憶體管理,包括linux虛擬對映以及glibc中malloc的實現 然後簡要介紹單程序多執行緒的記憶體管理方式,主要涉及各執行緒堆疊空間的分配 linux採用兩級保護機制,隔離核心空間和使用者程式空間,使使用者程式無法直接訪問核心,...