Linux總是以Lazy的方式給應(yīng)用程序分配內(nèi)存,包括堆、棧(函數(shù)調(diào)用越深,用的棧越多,最終發(fā)生page fault才得到棧)、代碼段、數(shù)據(jù)段。那么,這些已經(jīng)獲得到內(nèi)存的段會(huì)一直占用著內(nèi)存嗎?
1.page cache
Linux下讀寫(xiě)文件,主要有兩種方式:
調(diào)用read讀文件,Linux內(nèi)核會(huì)申請(qǐng)一個(gè)page cache,然后把文件讀到page cache中,再將內(nèi)核空間的page cache拷貝到用戶空間的buf。
調(diào)用write寫(xiě)文件,則將用戶空間buf拷貝到內(nèi)核空間page cache。
mmap
mmap可以避免buf從用戶空間到內(nèi)核空間的拷貝過(guò)程。
直接把文件映射成一個(gè)虛擬地址指針,這個(gè)指針指向內(nèi)核申請(qǐng)的page cache。內(nèi)核知道page cache與硬盤(pán)中文件的對(duì)應(yīng)關(guān)系。
使用mmap讀寫(xiě)文件
注:讀寫(xiě)權(quán)限需要對(duì)應(yīng),否則觸發(fā)page fault。
編譯執(zhí)行:
mmap看起來(lái)是由一個(gè)虛擬地址對(duì)應(yīng)一個(gè)文件(可以直接用指針訪問(wèn)文件),本質(zhì)上是把進(jìn)程的虛擬地址空間映射到DRAM(內(nèi)核從這片區(qū)域申請(qǐng)內(nèi)存做page cache),而這個(gè)page cache對(duì)應(yīng)磁盤(pán)中的某個(gè)文件,且Linux內(nèi)核會(huì)維護(hù)page cache和磁盤(pán)中文件的交換關(guān)系。詳見(jiàn)下圖:
page cache可以看作內(nèi)存針對(duì)磁盤(pán)的一個(gè)緩存,應(yīng)用程序在寫(xiě)文件時(shí),其實(shí)只是將內(nèi)容寫(xiě)入了page cache,使用sync才能真的寫(xiě)入文件。
ELF可執(zhí)行程序頭部會(huì)記錄代碼段的位置,代碼段的本質(zhì)就將ELF文件中的代碼段直接mmap映射到一個(gè)虛擬地址,且權(quán)限為R+X。
page cache可以極大的提高系統(tǒng)整體性能。如,進(jìn)程A讀一個(gè)文件,內(nèi)核空間會(huì)申請(qǐng)page cache與此文件對(duì)應(yīng),并記錄對(duì)應(yīng)關(guān)系,進(jìn)程B再次讀同樣的文件就會(huì)直接命中上一次的page cache,讀寫(xiě)速度顯著提升。但注意,page cache會(huì)根據(jù)LRU算法(最近最少使用)進(jìn)行替換。
演示:page cache對(duì)程序執(zhí)行時(shí)間的影響
第一次多出很多硬盤(pán)io操作;第二次python的很多環(huán)境都在內(nèi)存中命中了,速度提升顯著。用\time -v命令再次對(duì)比:
附注:
i.swap:
動(dòng)詞:swapping,內(nèi)存與磁盤(pán)的顛簸行為
名字:swap分區(qū)
ii.cache可以通過(guò)/proc/sys/vm/drop_caches強(qiáng)行釋放,寫(xiě)1釋放page cache,2釋放dentries和inode,3釋放兩者。
2.free命令的詳細(xì)解釋
上圖中,buffers與cached都是文件系統(tǒng)的緩存,沒(méi)有本質(zhì)區(qū)別,唯一區(qū)別是背景不同:
i.當(dāng)以文件系統(tǒng)(ext4,xfs等)的形式去訪問(wèn)文件系統(tǒng)中的文件,如mount /dev/sda1 /mnt后,/mnt目錄下會(huì)有很多文件,訪問(wèn)這類文件所產(chǎn)生的cache就對(duì)應(yīng)free命令顯示的cached列。
ii.直接訪問(wèn)/dev/sda1時(shí),如用戶程序直接打開(kāi)open(“dev/sda1…)或執(zhí)行dd命令,以及文件系統(tǒng)本身去訪問(wèn)裸分區(qū),所產(chǎn)生的cache對(duì)應(yīng)free命令顯示的buffers列。
參考下圖所示:
演示:讀硬盤(pán)裸分區(qū)導(dǎo)致free命令顯示內(nèi)容變化
linux kernel 3.14版本以后,已經(jīng)采用新的free命令,如下圖:
老版本free中-/+buffers/cache的含義如下圖:
新版本free中多出available,即是評(píng)估出現(xiàn)在還有多少內(nèi)存可供應(yīng)用程序使用。
3.file-backed的頁(yè)面和匿名頁(yè)
page cache和CPU內(nèi)部cache一樣,是可以被替換出去的。有文件背景的頁(yè)面可以swap到磁盤(pán)。EG. 啟動(dòng)firefox,跑一個(gè)oom的程序,前后對(duì)比f(wàn)irefox的smaps文件。可以看出firefox在內(nèi)存緊張的情況下,代碼段、mmap的字體文件等都被替換出去而不駐留內(nèi)存了。
那么,沒(méi)有文件背景的匿名頁(yè)是如何交換回收的呢?是否常住內(nèi)存?詳見(jiàn)下圖:
有文件背景的頁(yè)面和匿名頁(yè)都需要swap,有文件背景的頁(yè)面向自己的文件背景中交換,匿名頁(yè)向swap分區(qū)和swapfile中交換。即使編譯內(nèi)核時(shí)將CONFIG_SWAP關(guān)閉(只是關(guān)閉了匿名頁(yè)的交換),linux內(nèi)核中kswapd的線程還是會(huì)swap有文件背景的頁(yè)面。
Linux有三個(gè)水位:min,low,high。一旦內(nèi)存達(dá)到低水位時(shí),后臺(tái)自動(dòng)回收直到回收到高水位。當(dāng)內(nèi)存到達(dá)min水位時(shí),直接堵住進(jìn)程進(jìn)行回收。
匿名頁(yè)和有文件背景的頁(yè)面都有可能被回收,/proc/sys/vm/swappiness值比較大時(shí),傾向回收匿名頁(yè);swappiness值比較小時(shí)傾向回收有文件背景的頁(yè)面。回收算法皆為L(zhǎng)RU。
附注:
數(shù)據(jù)段比較特殊,在沒(méi)有寫(xiě)的情況是有文件背景的,但被寫(xiě)后就變?yōu)槟涿?yè)。
Windows中的虛擬內(nèi)存就相當(dāng)于Linux的swapfile。
4.頁(yè)面回收和LRU
如上圖,運(yùn)行到第4列時(shí),第1頁(yè)最不活躍。運(yùn)行到第5列時(shí)又把第1頁(yè)踏了一次,此時(shí)第2頁(yè)變?yōu)樽畈换钴S的。運(yùn)行到第6列時(shí)又把第2頁(yè)踏了一次,此時(shí)第3頁(yè)變?yōu)樽畈换钴S的,所以在第7列時(shí),由于要訪問(wèn)一個(gè)新的第5頁(yè),3就被替換出去。
5.swap以及zRAM
嵌入式系統(tǒng)受flash限制,很少使用swap分區(qū),一般都swapoff。所以嵌入式系統(tǒng)引入zRAM技術(shù)。
zRAM直接把一塊內(nèi)存模擬成一個(gè)硬盤(pán)分區(qū),當(dāng)作swap分區(qū)使用,此分區(qū)自帶透明壓縮功能,當(dāng)匿名頁(yè)向zRAM分區(qū)寫(xiě)時(shí),Linux內(nèi)核使CPU自動(dòng)對(duì)匿名頁(yè)進(jìn)行壓縮。接下來(lái),當(dāng)應(yīng)用程序又執(zhí)行到剛才的匿名頁(yè)時(shí),由于此頁(yè)已經(jīng)被swap到zRAM中,內(nèi)存中沒(méi)有命中,頁(yè)表也沒(méi)有命中,所以此時(shí)再去訪問(wèn)這塊內(nèi)存時(shí)再次發(fā)生page fault,Linux就從zRAM分區(qū)中將匿名頁(yè)透明的解壓出來(lái)還到內(nèi)存中。
zRAM的特點(diǎn)是用內(nèi)存來(lái)做swap分區(qū),透明壓(兩頁(yè)匿名頁(yè)有可能被壓縮成一頁(yè)),透明解(一頁(yè)解壓成兩頁(yè)),這樣其實(shí)相當(dāng)于擴(kuò)大了內(nèi)存,但會(huì)多損耗一些CPU。
-
Linux
+關(guān)注
關(guān)注
87文章
11511瀏覽量
213814 -
內(nèi)存管理
+關(guān)注
關(guān)注
0文章
168瀏覽量
14567
原文標(biāo)題:郝健: Linux內(nèi)存管理學(xué)習(xí)筆記-第4節(jié)課
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Linux內(nèi)存系統(tǒng): Linux 內(nèi)存分配算法
內(nèi)核的內(nèi)存是如何進(jìn)行分配的
如何通過(guò)TZASC分配安全內(nèi)存并通過(guò)OP-TEE中的可信應(yīng)用程序訪問(wèn)它?
Linux內(nèi)存管理中的Slab分配機(jī)制
嵌入式Linux NFS方式下應(yīng)用程序的實(shí)現(xiàn)
一種用于交互型CAD的內(nèi)存管理系統(tǒng)設(shè)計(jì)
Android應(yīng)用程序內(nèi)存泄漏的原因及規(guī)避方法

淺談內(nèi)存分配方式 避免內(nèi)存浪費(fèi)問(wèn)題
單片機(jī)的程序在內(nèi)存和FLASH中應(yīng)該如何進(jìn)行空間分配

嵌入式Linux應(yīng)用程序例程

C語(yǔ)言堆棧程序內(nèi)存的分配
Linux內(nèi)核引導(dǎo)內(nèi)存分配器的原理
OneCommand Manager應(yīng)用程序Linux版

評(píng)論