1. 程式人生 > >linux內核物理內存空間分布

linux內核物理內存空間分布

頂部 存儲文件 yuv 不可 文件內容 文本 列表 映射關系 以及

Linux 操作系統和驅動程序運行在內核空間,應用程序運行在用戶空間,兩者不能簡單地使用指針傳遞數據,因為Linux使用的虛擬內存機制,用戶空間的數據可能被換出,當內核空間使用用戶空間指針時,對應的數據可能不在內存中。

Linux內核地址空間劃分

通常32位Linux內核地址空間劃分0~3G為用戶空間,3~4G為內核空間。註意這裏是32位內核地址空間劃分,64位內核地址空間劃分是不同的。

1、x86的物理地址空間布局:

技術分享圖片

  物理地址空間的頂部以下一段空間,被PCI設備的I/O內存映射占據,它們的大小和布局由PCI規範所決定。640K~1M這段地址空間被BIOS和VGA適配器所占據。

  Linux系統在初始化時,會根據實際的物理內存的大小,為每個物理頁面創建一個page對象,所有的page對象構成一個mem_map數組。

進一步,針對不同的用途,Linux內核將所有的物理頁面劃分到3類內存管理區中,如圖,分別為ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。

  ZONE_DMA的範圍是0~16M,該區域的物理頁面專門供I/O設備的DMA使用。之所以需要單獨管理DMA的物理 頁面,是因為DMA使用物理地址訪問內存,不經過MMU,並且需要連續的緩沖區,所以為了能夠提供物理上連續的緩沖區,必須從物理地址空間專門劃分一段區 域用於DMA。

  ZONE_NORMAL的範圍是16M~896M,該區域的物理頁面是內核能夠直接使用的。

  ZONE_HIGHMEM的範圍是896M~結束,該區域即為高端內存,內核不能直接使用。

2、linux虛擬地址內核空間分布

技術分享圖片

  在kernel image下面有16M的內核空間用於DMA操作。位於內核空間高端的128M地址主要由3部分組成,分別為vmalloc area,持久化內核映射區,臨時內核映射區。

  由於ZONE_NORMAL和內核線性空間存在直接映射關系,所以內核會將頻繁使用的數據如kernel代碼、GDT、IDT、PGD、 mem_map數組等放在ZONE_NORMAL裏。而將用戶數據、頁表(PT)等不常用數據放在ZONE_ HIGHMEM裏,只在要訪問這些數據時才建立映射關系(kmap())。比如,當內核要訪問I/O設備存儲空間時,就使用ioremap()將位於物理 地址高端的mmio區內存映射到內核空間的vmalloc area中,在使用完之後便斷開映射關系。

3、linux虛擬地址用戶空間分布

技術分享圖片

  用戶進程的代碼區一般從虛擬地址空間的0x08048000開始,這是為了便於檢查空指針。代碼區之上便是數據區,未初始化數據區,堆區,棧區,以及參數、全局環境變量。

4、linux虛擬地址與物理地址映射的關系

技術分享圖片

  Linux將4G的線性地址空間分為2部分,0~3G為user space,3G~4G為kernel space。

  由於開啟了分頁機制,內核想要訪問物理地址空間的話,必須先建立映射關系,然後通過虛擬地址來訪問。為了能夠訪問所有的 物理地址空間,就要將全部物理地址空間映射到1G的內核線性空間中,這顯然不可能。於是,內核將0~896M的物理地址空間一對一映射到自己的線性地址空 間中,這樣它便可以隨時訪問ZONE_DMA和ZONE_NORMAL裏的物理頁面;此時內核剩下的128M線性地址空間不足以完全映射所有的 ZONE_HIGHMEM,Linux采取了動態映射的方法,即按需的將ZONE_HIGHMEM裏的物理頁面映射到kernel space的最後128M線性地址空間裏,使用完之後釋放映射關系,以供其它物理頁面映射。雖然這樣存在效率的問題,但是內核畢竟可以正常的訪問所有的物 理地址空間了。

5、buddyinfo的理解

cat /proc/buddyinfo 顯示如下:

Node 0, zone DMA 0 4 5 4 4 3 ...

Node 0, zone Normal 1 0 0 1 101 8 ...

Node 0, zone HighMem 2 0 0 1 1 0 ...

其中,Node表示在NUMA環境下的節點號,這裏只有一個節點0;zone表示每一個節點下的區域,一般有DMA、Normal和HignMem 三個區域;後面的列表示,夥伴系統中每一個order對應的空閑頁面塊。例如,對於zone DMA的第二列(從0開始算起),空閑頁面數為5*2^4,可用內存為5*2^4*PAGE_SIZE。

計算方法就是:

當前列的數字*2^列數*PAGE_SIZE 其中列數是從0開始計算的,即第一列是 當前列的數字*2^0*PAGE_SIZE

常見問題:

1、用戶空間(進程)是否有高端內存概念?

用戶進程沒有高端內存概念。只有在內核空間才存在高端內存。用戶進程最多只可以訪問3G物理內存,而內核進程可以訪問所有物理內存。

2、64位內核中有高端內存嗎?

目前現實中,64位Linux內核不存在高端內存,因為64位內核可以支持超過512GB內存。若機器安裝的物理內存超過內核地址空間範圍,就會存在高端內存。

3、用戶進程能訪問多少物理內存?內核代碼能訪問多少物理內存?

32位系統用戶進程最大可以訪問3GB,內核代碼可以訪問所有物理內存。

64位系統用戶進程最大可以訪問超過512GB,內核代碼可以訪問所有物理內存。

4、高端內存和物理地址、邏輯地址、線性地址的關系?

高端內存只和邏輯地址有關系,和邏輯地址、物理地址沒有直接關系。

5、為什麽不把所有的地址空間都分配給內核?

若把所有地址空間都給內存,那麽用戶進程怎麽使用內存?怎麽保證內核使用內存和用戶進程不起沖突?

由於所有用戶進程總的虛擬地址空間比可用的物理內存大很多,因此只有最常用的部分才與物理頁幀關聯。這不是問題,因為大多數程序只占用實際可用內存的一小部分。

在將磁盤上的數據映射到進程的虛擬地址空間的時,內核必須提供數據結構,以建立虛擬地址空間的區域和相關數據所在位置之間的關聯。例如,在映射文本文件時,映射的虛擬內存區必須關聯到文件系統的硬盤上存儲文件內容的區域。如圖所示:

技術分享圖片

當然,給出的是簡化的圖,因為文件數據在硬盤上的存儲通常並不是連續的,而是分布到若幹小的區域。內核利用address_space數據結構,提 供一組方法從後備存儲器讀取數據。例如,從文件系統讀取。因此address_space形成了一個輔助層,將映射的數據表示為連續的線性區域,提供給內 存管理子系統。

按需分配和填充頁稱為按需調頁法。它基於處理器和內核之間的交互,使用的各種數據結構如圖所示:

技術分享圖片

過程如下:

CPU將一個虛擬內存空間中的地址轉換為物理地址,需要進行兩步(如下圖):

首先,將給定一個邏輯地址(其實是段內偏移量,這個一定要理解!!!),CPU要利用其段式內存管理單元,先將為個邏輯地址轉換成一個線程地址,

其次,再利用其頁式內存管理單元,轉換為最終物理地址。

技術分享圖片

這樣做兩次轉換,的確是非常麻煩而且沒有必要的,因為直接可以把線性地址抽像給進程。之所以這樣冗余,Intel完全是為了兼容而已。

  • 進程試圖訪問用戶地址空間中的一個內存地址,利用上面的線性地址去查找頁表,確定對應的物理地址,但使用的頁表無法確定物理地址(物理內存中沒有關聯頁)
  • 處理器接下來觸發一個缺頁異常,發送到內核。
  • 內核會檢查負責缺頁區域的進程地址空間數據結構,找到適當的後備存儲器,或者確認該訪問實際上是不正確的(未映射,未使用)
  • 分配物理內存頁,並從後備存儲器讀取所需數據填充。
  • 借助於頁表將物理內存頁並入到用戶進程的地址空間,應用程序恢復執行。

這些操作對用戶進程是透明的。換句話說,進程不會註意到頁是實際在物理內存中,還是需要通過按需調頁加載。

技術分享圖片

在整個過程中可能需要解決以下幾個問題:

1)系統如何感知進程當前所需頁面不在主存(頁表機制);
2)當發現缺頁時,如何把所缺頁面調入主存(缺頁中斷機構);
3)在置換頁面時,根據什麽策略選擇欲淘汰的頁面(置換算法)。

頁表機制

技術分享圖片

狀態位(中斷位):標識該頁是否在內存(0或1);
訪問位:標識該頁面的近來的訪問次數或時間(換出);
修改位:標識此頁是否在內存中被修改過;
外存地址:記錄該頁面在外存上的地址,即(外存而非內存的)物理塊號。

缺頁中斷機制

程序在執行時,首先檢查頁表,當狀態位指示該頁不在主存時,則引起一個缺頁中斷發生,其中斷執行過程與一般中斷相同:
保護現場(CPU環境);
中斷處理(中斷處理程序裝入頁面);
恢復現場,返回斷點繼續執行。

linux內核物理內存空間分布