Linux內存管理(x86-32位系統)

linux內存的管理主要分爲兩部分,地址管理和存儲設備管理。下面針對這兩部分介紹一下我對內存管理的理解。linux

硬件地址的基本概念

  • DRAM域地址:是DRAM控制器所能訪問的地址空間集合。
  • PCI總線域地址:是PCI設備所能直接訪問的地址空間集合。
  • 存儲器域地址:是CPU所能訪問的地址空間集合。

結合下圖對上面概念進行解釋: ios

CPU訪問DRAM域或PCI總線域地址空間時,都須要進行地址轉換(將存儲器域地址轉換爲相應域的地址)。例如:CPU訪問DRAM域時,須要進行存儲器域地址空間到DRAM域地址空間的轉換(由DRAM控制器完成);CPU訪問PCI總線域時,須要進行存儲器域地址空間到PCI總線域地址空間的轉換(由HOST主橋完成)。函數

在x86處理器系統中,會將DRAM域和PCI總線域映射到存儲器域空間中,而且其大多數DRAM域中的地址與存儲器域中的地址一一對應並且相等,而存儲器域的PCI地址與PCI總線域的地址也一一對應並且相等。它們在存儲器域空間的映射彼此獨立,互不衝突,映射關係由BIOS提供(e820地址映射表)。code

PCI設備訪問DRAM域地址空間時,首先要通過HOST主橋將PCI總線域地址轉換爲存儲器域地址,而後再由DRAM控制器將存儲器域地址轉換爲DRAM域地址。進程

軟件地址的基本概念

  • 邏輯地址,是一個32位長的地址。全部進程地址都使用邏輯地址。內存

  • 線性地址(也稱爲虛擬地址),是一個32位長地址,能夠用來表示高達4G的地址,值的範圍從0x00000000到0xffffffff。它是經過分段單元的硬件電路將邏輯地址轉換爲線性地址,即將邏輯地址加上一個段起始地址就獲得了線性地址。在linux中,全部的段都從0x00000000開始,因此在linux下邏輯地址等於線性地址,即進程地址也是線性地址。後面咱們就再也不討論邏輯地址,而都使用線性地址表明進程所使用的地址。get

  • 物理地址,是經過分頁單元的硬件電路將線性地址轉換爲物理地址。該地址就是上面所說的存儲器域地址,是CPU所能訪問的地址空間的集合內存管理

下面用圖對上面概念進行解釋: io

在X86系統中,全部進程都使用的是邏輯地址,它要經過分段單元硬件電路轉換爲線性地址,再經過分頁單元硬件電路轉換爲物理地址(即存儲器域地址)。變量

分段單元的邏輯以下圖所示(將邏輯地址轉換爲線性地址)

分頁單元的邏輯以下圖所示(將線性地址轉換爲物理地址)

地址管理

linux將線性地址空間分爲user和kernel兩個空間

  • USER線性地址空間,指的是可被應用層訪問的線性地址空間。其大小(32位處理器) = 4G - KERNEL線性地址空間大小。

  • KERNEL線性地址空間,指的是可被內核使用的線性地址空間。其大小 = LOWMEM線性地址空間大小 + VMALLOC線性地址空間大小。

    * LOWMEM線性地址空間,它佔用了KERNEL線性地址空間中的一部分。其大小 = KERNEL線性地址空間大小 - VMALLOC線性地址空間大小 。
     * LOWMEM功能,這段地址空間在啓動時已作好地址映射,其映射的物理內存是連續的,並與物理內存地址一一對應。
     * VMALLOC線性地址空間,它佔用了KERNEL線性地址空間中的另外一部分。其大小 = (KERNEL線性地址空間大小 - 物理內存大小) >  __VMALLOC_RESERVE ?KERNEL線性地址空間 - 物理內存大小 :  __VMALLOC_RESERVE
     * VMALLOC功能,用於在內核中分配線性地址連續,但物理地址不需連續的大內存區。這段地址空間初始化時未作任何地址映射。

linux內核線性地址空間變量的含義

  • PAGE_OFFSET = __PAGE_OFFSET = CONFIG_PAGE_OFFSET:這個值是用於劃分USER線性地址和KERNEL線性地址的分界點。

  • __VMALLOC_RESERVE:表示爲VMALLOC線性地址空間最小應保留的空間大小,默認是128M。這個值可在系統啓動時經過內核參數vmalloc來改變。

  • VMALLOC_END:VMALLOC線性地址空間的結束地址。其值 = 最大線性地址 – 其它ROM內存空間大小

  • VMALLOC_START:VMALLOC線性地址空間的起始地址。其值 = VMALLOC_END - VMALLOC線性大小(最小爲VMALLOC_RESERVE)

  • VMALLOC_OFFSET:固定大小爲8M,用於再LOWMEM線性地址空間和VMALLOC線性地址空間之間創建一個隔離帶,防止它們互相影響。

  • MAXMEM:其值爲(VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE),表示內核可以直接映射的最大RAM容量,這個值也是相對固定的(與物理內存實際的大小沒有關係),由於VMALLOC_END、PAGE_OFFSET、 __VMALLOC_RESERVE是相對固定的。

  • MAXMEM_PFN:其值爲PFN_DOWN(MAXMEM),表示內核可以直接管理的內存頁個數。

  • MAX_ARCH_PFN:表示CPU最大可訪問的內存頁數。對應32位CPU,若是其開啓了PAE,則MAX_ARCH_PFN=(1ULL<<(36-PAGE_SHIFT))。若是未開啓PAE,則MAX_ARCH_PFN=(1ULL<<(32-PAGE_SHIFT))

  • max_pfn:是從bios發現的最大的能管理的內存頁個數, 與實際內存大小有關,但它的大小不能超過MAX_ARCH_PFN。 當max_pfn <= MAXMEM_PFN時說明實際的物理內存比內核可以線性映射的內存數小,此時就不須要Highmem來管理了。此時就算開啓了HIGHMEM,ZONE_HIGHMEM區可以管理的內存大小也是0。 當max_pfn > MAXMEM_PFN時說明實際的物理內存比內核可以線性映射的內存數大,這樣多餘的那部分物理內存就不能進行線性映射了,必須經過頁表映射(即vmalloc來管理), 該物理內存應該由ZONE_HIGHMEM區來管理。而若是沒有開啓HIGHMEM選項,則這部份內存就丟失了,再也不被管理。

  • max_low_pfn:低端內存(相對於highmem)的最大頁數,這個就是ZONE_NORMAL區能管理的最大頁數。 若是實際物理內存比內核可以線性映射的內存數小,max_low_pfn = max_pfn,即全部的內存都歸低端內存區管理。 若是實際物理內存比內核可以線性映射的內存數大,max_low_pfn = MAXMEM_PFN,即低端內存區可以管理的最大值就是內核可以線性映射的最大值。

  • highmem_pages:高端內存的最大頁數,這個是就是ZONE_HIGHMEM區管理的最大頁數。其值爲(max_fn – max_low_pfn)。

存儲設備管理(便可使用物理內存空間的管理)

linux內核將物理內存空間進行功能區劃分(劃分時要參考地址管理中線性地址的分配),並經過page結構進行管理

  • ZONE_DMA物理內存空間,在x86體系結構上它是0~16M的內存範圍。由page結構進行管理,這個區包含的頁能被老設備執行DMA操做。

  • ZONE_NORMAL物理內存空間,在x86體系上它是16M~KERNEL->LOWMEM線性地址對應的內存範圍。由page結構進行管理。 (內核在啓動時,就已經將上面這兩個區的內存空間映射到KERNEL線性地址空間中了。因此內核不需作任何操做,就能夠直接訪問這些物理內存。但爲了保證所訪問內存頁沒有被其它功能使用,所以在訪問內存以前,要使用get_free_page()等函數獲取空閒頁,並將該頁標記爲使用。返回的物理頁不須要作任何地址映射,僅僅是將物理地址加上內核空間偏移量就得到了其線性地址)

  • ZONE_HIGHMEM物理內存空間,其大小 = 實際物理內存大小 – KERNEL->LOWMEM線性地址空間大小。由page結構進行管理,用於管理物理內存大小超過KERNEL->LOWMEM線性地址空間大小之外的物理內存。這段內存空間沒有被映射到內核線性地址空間,在使用時,要經過alloc_page()分配一個page頁,而後再將該頁映射到線性地址空間,這樣才能經過線性地址訪問。內核(一般用vmalloc()函數)將HIGHMEM物理內存頁映射到VMALLOC線性地址空間,所以內核可以使用的HIGHMEM物理內存大小與VMALLOC線性地址空間大小有關。另外,HIGHMEM物理內存頁一般被映射到USER線性地址空間。

  • ZONE_NORMAL 與ZONE_HIGHMEM主要的區別是ZONE_NORMAL中的物理內存不須要作頁表映射直接用就好了,其線性地址的最大值是MAXMEM。而ZONE_HIGHMEM中的物理內存須要作頁表映射才能使用,其線性地址的範圍是VMALLOC_START~VMALLOC_END。因此不能作線性映射的內存都歸ZONE_HIGHMEM來管理了。若是開啓的HIGHMEM選項,則ZONE_HIGHMEM的大小就是剩下的物理內存,若是沒開起,則這部分物理內存就沒法管理了。

相關文章
相關標籤/搜索