歡迎光臨
每天分享高質量文章

Linux 記憶體的分配和釋放

來源:暗無天日,

lujun9972.github.io/blog/2018/04/18/linux記憶體的分配和釋放/

瞭解記憶體分配機制(共享對映與請求分頁)

透過 pmap 命令,可以獲取使用者行程邏輯地址空間中對映的記憶體資訊:

pmap -x $pid

其中 -x 表示獲取詳細資訊。

下麵是一個例子:

pmap -x $(pidof emacs) |head -20

其中,“Address(地址)”指的行程的邏輯地址空間。

“Kbytes”串列示的是對應邏輯地址的容量,以Kb為單位

“RSS”串列示的是實際使用的物理記憶體容量,由於分頁機制的存在,這個值一般要比”Kbytes”的值要少。

“Mapping”列為邏輯記憶體的對映方式,其中”[annon]“表示透過malloc函式來分配的堆空間(匿名記憶體),”[stack]“為行程的棧空間,這兩種對映都是將物理記憶體對映到行程的邏輯記憶體上去。 而”emacs-25.3″,”libpixbufloader-svg.so”等檔案名則表示它們執行的是檔案對映,他們對應的是磁碟上的檔案。當這些檔案被讀入高速快取後,相應的記憶體空間被對映成行程的邏輯記憶體。

當出現多個程式共同使用相同的檔案對映(共享庫)時,它們可以共享磁碟高速快取中的同一空間,從而節省物理記憶體的使用量,這種技術就是”共享對映”技術。

除了共享庫外,行程的fork也使用了共享對映技術。 當父行程fork子行程時,Linux核心並不對記憶體中的內容進行實際上的複製,而是將對映到父行程邏輯地址空間內的那部分內容原封不動地共享對映到子行程的邏輯地址空間內。 但為了防止父行程和子行程的記憶體操作相互影響,Linux核心在進行共享對映時,相應的記憶體區域會暫時設定為防寫。 當某一方行程試圖操作記憶體時,會引發只讀異常。核心檢測到這個異常後,會複製操作的這個記憶體頁,從而使兩個行程都可進行獨立寫入。 這種在寫入時複製的機制叫做“寫時複製(copy-on-write)”

另一方面,行程將可執行檔案或共享庫檔案內容讀入記憶體並對映到行程邏輯地址空間上時,並不會讀入全部的檔案內容,而是先標記”該檔案的內容已經被對映到邏輯地址空間內”. 當行程訪問邏輯地址空間時,由於不存在對應的物理記憶體,會引發換頁錯誤的異常。內容檢測到該異常後會將所需部分以記憶體頁為單位讀入記憶體中。 這種只讀入所需內容的機制,叫做請求分頁。

瞭解記憶體釋放機制

當其他行程需要新的物理記憶體時,就涉及到如何將尚有資料殘餘的物理記憶體釋放或換出來的問題了。

當需要新物理記憶體時,會優先釋放Inactive(file)和Active(file)中記錄的記憶體頁,只需要將臟資料寫入檔案中再釋放記憶體頁即可。

而Inactive(anon)和Active(anon)記憶體頁則需要將內容交換到物理磁碟上的swap中後再釋放。 具體來說,Linux會在行程頁表上做一個標記,標記出換出記憶體所對應的邏輯地址。 當行程訪問該邏輯地址時,會產生相應物理記憶體不存在的異常,Linux核心檢測到這個異常後,會再次將資料從swap中載入入空閑記憶體,並重新配置頁表資訊。

Linux核心使用兩種機制來加快換出處理速度:

  • 一種是預讀。

當某一個記憶體頁需要換入時,Linux核心會將其後的幾個記憶體頁一起換入。因為行程連續訪問多個記憶體頁的可能性很大。預讀的頁數為核心引數 vm.page-cluster 決定為 2^vm.page-cluster.

  • 另一種是交換快取。

即在換入某個記憶體頁後,物理磁碟上交換空間中仍然保留原資料,這種狀態的記憶體會記錄在“交換快取”的串列上。這樣當需要再次換出記錄在“交換快取”上的記憶體頁的資料時,就無需再次換入了。

每個行程的記憶體使用情況可以透過檢視 /proc/行程ID/status 來檢視

cat /proc/$(pidof emacs)/status

Name: emacs

Umask:  0022

State:  S (sleeping)

Tgid: 6769

Ngid: 0

Pid:  6769

PPid: 1

TracerPid:  0

Uid:  1000  1000  1000  1000

Gid:  1000  1000  1000  1000

FDSize: 64

Groups: 986 998 1000

NStgid: 6769

NSpid:  6769

NSpgid: 6769

NSsid:  6769

VmPeak:   567040 kB

VmSize:   567040 kB

VmLck:         0 kB

VmPin:         0 kB

VmHWM:    241176 kB

VmRSS:    241176 kB

RssAnon:    204544 kB

RssFile:     36604 kB

RssShmem:       28 kB

VmData:   231712 kB

VmStk:      1596 kB

VmExe:      2332 kB

VmLib:     47832 kB

VmPTE:      1008 kB

VmSwap:        0 kB

HugetlbPages:        0 kB

CoreDumping:  0

Threads:  4

SigQ: 1/15456

SigPnd: 0000000000000000

ShdPnd: 0000000000000000

SigBlk: 0000000000000000

SigIgn: 0000000004381000

SigCgt: 00000001db816eff

CapInh: 0000000000000000

CapPrm: 0000000000000000

CapEff: 0000000000000000

CapBnd: 0000003fffffffff

CapAmb: 0000000000000000

NoNewPrivs: 0

Seccomp:  0

Cpus_allowed: 3

Cpus_allowed_list:  0-1

Mems_allowed: 1

Mems_allowed_list:  0

voluntary_ctxt_switches:  12951

nonvoluntary_ctxt_switches: 21641

其中比較有用的項有:

VmData

data段的大小

VmExe

text段的大小

VmHWM

當前物理記憶體使用量的最大值

WmLck

用mlock鎖定的記憶體大小

VmLib

共享庫的使用量

VmPTE

頁面表的大小

VmPeak

當前物理記憶體的最大值

VmRSS

物理記憶體的實際使用量

VmSize

邏輯地址的大小

VmStk

堆疊的大小

VmSwap

交換空間的使用量


●編號493,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

運維

更多推薦18個技術類公眾微信

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂