Linux記憶體管理系列之二 物理記憶體分配機制

2021-08-15 11:15:17 字數 2826 閱讀 7366

記憶體是計算機的重要組成部分,它是一種物理介質,它的訪問速度介於cpu與磁碟之間。它的主要作用是用來交換資料,即將磁碟組的資料通過記憶體讀入cpu,同時將cpu操作後的資料通過記憶體寫入磁碟。

在當下的linux中,記憶體主要包括:核心空間記憶體與使用者空間記憶體。這兩部分的記憶體全部由linux核心管理。我們首先來看核心是如何管理物理記憶體的。

一  頁與區的概念

1:物理記憶體分頁

在linux中,核心通常把頁作為處理記憶體的基本單位,但是真正的物理記憶體中並沒有做硬體上的分頁操作,頁只是邏輯上的概念。我們在核心中定義乙個資料結構page用來表示記憶體中的內個物理頁。其內部結構如圖1-1所示:

圖 1-1

其中flags域代表當前頁的狀態,通常表示頁是否為臟,或該頁是否被鎖定在記憶體中。關於髒頁是指在快取記憶體中的頁資料與磁碟檔案中的物理資料不一致,則該頁為臟頁,且該頁的記憶體不可以被核心**。記憶體鎖定某個頁,是指程序訪問記憶體時是通過page結構體,而在交換分割槽處理時有的page結構體會被換到磁碟中,程序訪問記憶體時在記憶體中找不到page就得去磁碟中尋找,這樣訪問速度會下降。核心可以把固定的page結構體鎖定到記憶體中,這樣程序訪問記憶體時就不必去訪問磁碟。

_count域指頁的引用計數,當計數值為-1時表示核心沒有引用該頁,通常情況下乙個物理頁可以被多個程序引用。乙個頁的擁有者可以使核心執行緒,使用者態程序,動態分配的核心資料,靜態核心**或者頁快取記憶體。

virtual域指的是頁的虛擬位址,我們知道任何程序都是無法直接訪問實體地址的,程序訪問記憶體,首先是訪問虛擬位址,然後通過頁表轉化成對應的實體地址才能訪問到最終的資料單元。

在多程序中由於程序之間的切換,每一次重新獲得的記憶體的實體地址都會不同,所以page與固定大小記憶體的對映也是短暫的。這種現象稱為記憶體的重定位。通常情況下乙個物理頁大小的記憶體為4kb,而乙個page的大小約為40b。

2:物理記憶體分割槽

在物理記憶體中,由於硬體的限制。核心訪問記憶體頁的速度也不一致,導致的結果是:硬體只能對部分記憶體區執行dma操作,即硬體不經過cpu直接訪問記憶體;某些體系結構中記憶體的物理定址範圍大於虛擬定址範圍,部分記憶體不能永久對映到核心空間上。

鑑於上述問題,linux對記憶體採取分割槽策略,主要將記憶體分成3個區:區描述

物理記憶體

zone_dma

dma使用的頁

<16mb

zone_normal

可以正常定址的頁

16~896mb

zone_highmem

動態對映的頁

>896mb

在分配物理頁時需要注意,一般情況下不允許跨區域分配記憶體,即乙個頁跨越dma區和normal區,這樣會導致同乙個頁內部資料的訪問速度不一致。與頁相似,每個區也提供一種結構體zone用來表示,如下圖1-2:

圖 1-2

其中lock域表示自旋鎖,用來做同步訪問操作。

watermark域表示該記憶體區的記憶體消耗基準。

name是記憶體區的命名,包括:dma,normal,highmem。

二 記憶體的分配與釋放

通常我們在c語言程式設計中往往使用malloc與free為程序分配與釋放使用者空間的記憶體,我們來研究核心底層是如何分配與釋放記憶體空間的。

1 記憶體的分配

前面我們講過核心對物理記憶體進行分頁操作,將物理記憶體分為4kb大小的塊,因此在起初的記憶體分配中,頁作為最小的分配單元來操作。

struct page* alloc_pages(gfp_t gfp_mask,unsigned int order)

該函式用來分配2^ order大小個連續的物理頁,同時返回乙個指標指向第乙個頁的page結構體。這裡的gfp_t引數通常指分配器標誌,一般情況下包括:行為修飾符,區修飾符和型別。這裡重點**型別標誌中的gfp_kernel與gfp_atomic。核心中常用的標誌是gfp_kernel,它代表了在分配器分配記憶體的過程中會存在分配器睡眠的情況,會產生阻塞。這種標誌通常用來為普通優先順序的程序分配記憶體,在分配的過程中可以被阻塞,分配成功的機率比較大。而gfp_atomic標誌表示記憶體分配原子操作,即在分配的過程中,分配器不能睡眠,這種分配方式通常用於中斷處理,因為正常情況下中斷程式不允許記憶體分配器阻塞。即該操作有原子性,要麼分配完成要麼完全不分配。這種記憶體的分配方式成功率表較低。

重所周知,在4gb的記憶體中,核心記憶體只能佔到1gb,所以在alloc_pages函式中這種按頁分配記憶體的方式是非常奢侈的,在實際工作中會造成很大的記憶體浪費,隨後linux提出了一種新的按位元組分配記憶體的方式該函式如下:

void *kmalloc(size_t size,gfp_t flags)

void *vmalloc(unsigned long size)

這種分配方式在虛擬位址上是連續的,不一定保持實體地址的連續。目前核心為了維持高效能,一般都採用kmalloc方式分配記憶體,只有當需要的記憶體塊過大,核心才會轉用vmalloc方式分配記憶體。

2  記憶體的釋放

與記憶體的分配相對應,記憶體同樣需要釋放,記憶體釋放函式與記憶體分配函式成對出現。目前通常用到的記憶體釋放函式包括:_free_pages,kfree,vfree。我們重點來**一下_free_pages(struct page* page, unsigned int order)。

在程式釋放記憶體時,我們需要謹慎處理,一般情況下我們不能越界釋放記憶體正如不能越界訪問一樣。_free_pages函式的第乙個引數page代表要釋放連續物理塊的首頁位址,order代表要釋放2^order個頁。在釋放頁之前要首先進行錯誤檢查,先保證要釋放的頁都在程序的位址範圍之內,然後再執行_free_pages操作,否則直接報錯,避免系統崩潰。

Linux記憶體管理之二 記憶體節點和記憶體分割槽

uma和numa uma uniform memory access 即一致性記憶體訪問。這種情況下,cpu訪問記憶體的任何位置,代價都是一樣的。numa non uniform memory access 即非一致性記憶體訪問。這種情況下,cpu訪問不同位置的記憶體,代價是不一樣的。在多cpu情況...

物理記憶體管理

linux核心管理物理記憶體是通過分頁機制實現的,它將整個記憶體劃分成無數個4k 在i386體系結構中 大小的頁,從而分配和 記憶體的基本單位便是記憶體頁了。系統在分配記憶體時不再要求大塊的連續記憶體,但是實際上系統使用記憶體時還是傾向於分配連續的記憶體塊。為了儘量減少不連續情況,核心採用了 夥伴 ...

Linux 記憶體管理 線性空間與物理記憶體

linux 記憶體管理 線性空間與物理記憶體 收藏 上圖反映了如下資訊 1 程序的4g 線性空間被劃分成三個部分 程序空間 0 3g 核心直接對映空間 3g high memory 核心動態對映空間 vmalloc start vmalloc end 2 三個空間使用同一張頁目錄表,通過 cr3 可...