正文
0 內存模塊
1 linux內存總體布局:內存分成用戶態(tài)和內核態(tài)
4G進程地址空間解析
內核地址空間
進程地址空間
2 地址轉換和頁表
2.1 地址轉換
虛擬內存是指程序使用的邏輯地址习瑰。每個進程4G。所有進程共享物理內存4G,所以邏輯地址和物理地址不是一一對應悔据,需要地址轉換.
頁表由3部分組成:頁目錄辣卒,頁面顽耳,頁內偏移
32bit只有3級 0 -11位:頁內偏移OFFSET 12-21位:頁面表偏移PT(PTE 頁表項.指向一張具體的物理內存頁) 22-31位:頁面目錄偏移PGD
尋址過程如下:
1)操作系統(tǒng)從寄存器CR3獲得當前頁面目錄指針(基地址)扼菠;
2)基地址+頁面目錄偏移->頁面表指針(基地址)尼荆;
3)頁面表指針+頁面表偏移->內存頁基址;
4)內存頁基址+頁內偏移->具體物理內存單元诈泼。
頁號=邏輯地址/頁面大邢裳痢;頁面偏移量=邏輯地址%頁面大小 娶桦。
頁目錄保存頁表項的地址,頁表項保存物理地址,最后1項保存4k頁內偏移。
進程頁表長這樣子:
舉例說明地址映射:比如要訪問線性地址0xBFC0 4FFE(1byte),2進制形式
1).mmu先取線性地址高10位(31-22)=767忿墅,x4=3068=0xBFC疚脐,+cr3=0x3800 0bfc,即頁目錄項在內存的地址呼畸,此地址的內容0x392f f000即頁表首地址(頁對齊最后12位清0)
2).mmu取線性地址下面10位數(shù)(21-12)=4蛮原,x4=16=0x10板熊,+0x392f f000=0x392f f010干签,即頁表項在內存的地址喘沿,此地址的內容0x3080 4000即物理頁面的首地址(頁對齊最后12位清0)
3).mmu取線性地址最后12位數(shù)(11-0)=4094=0xffe作為低12位,0x3080 4000的前20位作為高20位,組成一個新的32位數(shù)0x3080 4ffe即線性地址0xBFC0 4FFE對應的物理地址
2.2 內核頁表和進程頁表的區(qū)別和聯(lián)系忆绰?
進程頁表訪問:虛擬內存與物理內存的對應。 內核頁表:建立物理內存和disk的對應.address_space稚茅。
mmap的時候萎馅,vmalloc分配內核內存糜芳,更改內核頁表晃虫,然后拷貝內核頁表到進程頁表.
無論進程頁表還是內核頁表都在內核中運行,都由內核修改.
經(jīng)典問題:兩個進程虛擬地址相同,物理地址不同滥比。本質就是進程頁表的內容不同。
3 內存的分配
3.1 伙伴系統(tǒng) and slab
伙伴系統(tǒng)分配的最小單位是頁(4k). 伙伴系統(tǒng)是一個內存池.
它把所有的空閑頁框分組為11個塊鏈表寺滚,每個塊鏈表分別包含大小為1酒奶,2纺阔,4笛钝,8中贝,16邻寿,32挡毅,64段磨,128,256沐序,512和1024個連續(xù)的頁框.
把空閑的頁以2的n次方為單位進行拆分or合并.分配從鏈表上獲取和歸還.
比如:k 鏈表(32)沒有空閑塊,需要在k+1鏈表(64)查找,如果仍然沒有唐含。在k+2鏈表(128)查找,找到以后分成1個64,2個32發(fā)給k和k+1鏈表.
鏈表回收過程相反,臨近的空閑塊組合,連接到空閑鏈表上.
例如:假設ZONE_NORMAL 有16頁內存淮捆,此時有人申請一頁內存,剩下15頁.Buddy算法會把剩下的15頁拆分成8+4+2+1案站,放到不同的鏈表中去蟆盐。
slab:內核分配內存通常很小誊稚,所以引入了slab的方法. Buddy解決外部內存碎片,slab 解決內部內存碎片.
伙伴系統(tǒng)(buddy system)是以頁為單位管理和分配內存.slab是以byte為單位分配內存.
slab分配器是基于對象類型進行內存管理的,每一種對象被劃分為一類,例如索引節(jié)點對象是一類,進程描述符又是一類肩碟,等等 slab分成2種cache,普通cache和專用cache. 每種cache分成3種鏈表full,paritition,empty.
slab 使用kmalloc分配.
伙伴系統(tǒng)就是內存池.slab是從伙伴系統(tǒng)批發(fā)的內存建立的小內存池.
3.2 內存分配
內存分配就是向伙伴系統(tǒng)申請內存,然后更改頁表形成地址轉換.
缺頁中斷:malloc分配內存即產(chǎn)生缺頁中斷,缺頁中斷有兩個情況网杆,一種有足夠內存严里,直接分配座柱。另一種情況沒有內存戏锹,需要先置換后分配.
(1) 進程分配malloc
malloc 分配的最小單位是頁.小于128k用brk.malloc 大于128k用mmap.
1): brk原理:brk是堆頂指針,會產(chǎn)生內存空洞.比如:先分配256k盯荤,再分配128k绍哎,釋放前面的256k,因為brk指向的棧頂128k沒有回收盾似,所以釋放的256k頁不會歸還os.
brk釋放:當brk釋放空間少于128k則不會歸還os,而是malloc采用鏈表管理這些空閑內存.
比如:malloc(1) 分配1個字節(jié),os也會分配4k他嚷。剩下的4k-1字節(jié)全由malloc的空閑內存管理鏈表管理.
2): mmap
堆和棧之間鹊奖,獨立分配震缭,直接釋放. 采用匿名映射分配內存. 缺點在堆棧之間造成內存空洞赂毯。
寫拷貝:malloc分配內存僅僅分配虛擬內存并沒有分配物理內存,根據(jù)內存的寫拷貝原則拣宰,只有訪問內存的時候才正式分配物理內存党涕。即malloc分配虛擬內存,memset的時候才真正分配物理內存.
(2) 內核分配內存
1 ) vmalloc
適用場景:在內核中不需要連續(xù)的物理地址,而僅僅需要內核空間里連續(xù)的虛擬地址的內存塊. 比如:將文件讀入內核內存.
適用區(qū)域: vmalloc 機制則在高端內存映射區(qū)分配物理內存.
通過更改內核頁表實現(xiàn)內核內存和物理地址的地址轉換. vmalloc是從伙伴系統(tǒng)分配內存.
2 ) kmalloc
kmalloc是實地址映射,不需要地址轉換.
kmalloc基于slab分配器,slab緩沖區(qū)建立在一個連續(xù)的物理地址的大塊內存之上晌该,所以緩沖對象也是物理地址連續(xù)的肥荔。
3 ) malloc,vmalloc,kmallc 分配流程
3.3 置換和回收
(1)兩種情況
一種釋放绿渣,一種PFRA(類似jvm 垃圾回收內存機制)
(2)頁分類(按有無文件背景頁面主要分兩種):
文件頁(file-backed page):有文件背景頁面⊙喙ⅲ可以直接和硬盤對應的文件進行交換中符。
匿名頁(anonymous page):無文件背景頁面.如進程堆,棧,數(shù)據(jù)段使用的頁等,無法直接跟磁盤交換,但是可以跟swap區(qū)進行交換.
(3)哪些內存可以回收
a ) 屬于內核的大部分頁框是不能夠進行回收的,比如內核棧誉帅、內核代碼段舟茶、內核數(shù)據(jù)段以及大部分內核使用的頁框。
b ) 進程使用的頁框可以進行回收的,比如進程代碼段,進程數(shù)據(jù)段,進程堆棧,進程訪問文件時映射的文件頁,進程間共享內存使用的頁.
c ) 伙伴系統(tǒng)分配的頁面使用者使用free_pages之類的函數(shù)主動釋放的,頁面釋放后被直接放歸伙伴系統(tǒng) slab中分配的對象(使用kmem_cache_alloc函數(shù)),也是由使用者主動釋放的(使用kmem_cache_free函數(shù)).
(4) 頁回收方式
a ) 頁回寫:如果一個很少使用的頁的后備存儲器是一個塊設備(例如文件映射),則可以將內存直接同步到塊設備,騰出的頁面可以被重用 頁交換:如果頁面沒有后備存儲器堵第,則可以交換到特定swap分區(qū),再次被訪問時再交換回內存隧出。
b ) 頁丟棄:如果頁面的后備存儲器是一個文件,但文件內容在內存不能被修改(例如可執(zhí)行文件),那么在當前不需要的情況下可直接丟棄踏志。
頁面該回收: 磁盤高速緩存的頁面,但是如果頁面是臟頁面胀瞪,則丟棄之前必須將其寫回磁盤 回收匿名映射的頁面针余,只好先把頁面上的數(shù)據(jù)轉儲到磁盤,這就是頁面交換(swap)凄诞。 所有的磁盤高速緩存頁面都可回收圆雁,所有的匿名映射頁面都可交換。
(5) 頁回收算法-LRU
磁盤高速緩存頁面(包括文件映射頁面)的鏈表帆谍、匿名映射頁面的鏈表 當Linux系統(tǒng)內存有盈余時伪朽,內核會盡量多地使用內存作為page cache,提高系統(tǒng)性能汛蝙,page cache會被加入到文件類型的LRU鏈表中,當系統(tǒng)內存緊張時烈涮,會按一定的算法來回收內存.
下面簡單了解下: LRU鏈表按zone來配置,每個zone中都有一整套LRU鏈表.page交換調度策略使用.page可能被調度到active_list或者inactive_list隊列里.就是使用lru這個list_head. LRU每個zone有兩個鏈表,一個active,一個non-active.
進行頁面回收的時候窖剑,一是將active鏈表中最近最少使用的頁面移動到inactive鏈表坚洽、二是嘗試將inactive鏈表中最近最少使用的頁面回收.
(6) 頁回收時機
直接頁面回收(主動觸發(fā)):“內存嚴重不足”事件的觸發(fā)。 周期性回收(被動觸發(fā)):kswapd進程以水線為觸發(fā)點西土,按LRU鏈表來進行回收讶舰。系統(tǒng)會調用函數(shù)balance_pgdat(),它主要調用的函數(shù)是 shrink_zone() 和 shrink_slab()需了。
(7) 反向映射(比如共享文件或者內存)
本質是逆向映射跳昼。
正向映射是建立進程頁表和物理內存關系用于訪問。
逆向映射是回收的時候,查看反向指針rmap,沒有頁表引用就回收.
多個引用的回收 PFRA處理頁面回收的過程中肋乍,LRU的inactive鏈表中的某些頁面可能就要被回收了庐舟。
如果頁面沒有被映射,直接回收到伙伴系統(tǒng)即可(對于臟頁住拭,先寫回挪略、再回收)历帚。
否則,還有一件麻煩的事情要處理。因為用戶進程的某個頁表項正引用著這個頁面呢杠娱,在回收頁面之前挽牢,還必須給引用它的頁表項一個交待 內核建立了從頁面到頁表項的反向映射。通過反向映射可以找到一個被映射的頁面對應的vma摊求,通過vma->vm_mm->pgd就能找到對應的頁表禽拔。然后通過page->index得到頁面的虛擬地址。再通過虛擬地址從頁表中找到對應的頁表項室叉。
(8) OOM( out of memory )killer
如果操作系統(tǒng)在進行了內存回收操作之后仍然無法回收到足夠多的頁面以滿足上述內存要求睹栖,那么操作系統(tǒng)只有最后一個選擇,那就是使用 OOM( out of memory )killer茧痕,它從系統(tǒng)中挑選一個最合適的進程殺死它野来,并釋放該進程所占用的所有頁面
4 內存實現(xiàn)
5 內存與文件系統(tǒng)
struct | 作用 |
---|---|
struct file* fd_array[] | 用于每個進程打開的文件的指針 |
struct file* vm _file | 用于一個vm_area_struct中all打開文件的指針.vm_file通過struct file中的struct path與struct dentry相關聯(lián). |
address_space | 一個文件對應一個address_space,address_space管理這個文件的所有頁緩存踪旷。通過radix樹管理. |
innode | 一個文件對應唯一inode struct |
struct dentry | 通過它的inode指針指向inode,inode與address_space一一對應曼氛,至此形成了頁緩存與文件系統(tǒng)之間的關聯(lián); |
vm_ops | 文件操作 open,close,nopage |
頁緩存和address_space
比如:進程A將文件A讀入內核頁緩存,然后address_space管理這些頁緩存令野。進程B也要讀文件A,它會現(xiàn)在address_space中查找如果存在則直接返回,如果不存在則從文件系統(tǒng)讀入. 有了address_space可以多個進程共享讀取文件.
如果兩個進程訪問一個文件,其中一個進程寫文件舀患,那么采用匿名文件方式.
6 共享內存
1 mmap 有2個功能:
(1) malloc 底層實現(xiàn). 參見上文
(2) 映射文件讀寫. 本質是進程可以訪問內核內存,減少了read,write函數(shù)所需要的內核拷貝到用戶態(tài).請看[https://blog.csdn.net/fdsafwagdagadg6576/article/details/107584821]
2 shm*() 函數(shù)气破。就是匿名文件
7 內存零拷貝技術
linux下的mmap和零拷貝技術fdsafwagdagadg6576的專欄-CSDN博客零拷貝和mmap
8 源碼實現(xiàn)
1) 結構體定義
內存描述符由mm_struct
結構體表示
struct mm_struct
{
struct vm_area_struct *mmap;
rb_root_t mm_rb;
atomic_t mm_users;
atomic_t mm_count;
struct list_head mmlist;
...
};
- mm_users:代表正在使用該地址的進程數(shù)目聊浅;
- mm_count: 代表mm_struct的主引用計數(shù),當該值為0說明沒有任何指向該mm_struct結構體的引用现使,結構體會被撤銷狗超。
- mmap和mm_rb:描述的對象都是相同的
- mmap以鏈表形式存放, 利于高效地遍歷所有元素
- mm_rb以紅黑樹形式存放朴下,適合搜索指定元素
- mmlist:所有的mm_struct結構體都通過mmlist連接在一個雙向鏈表中努咐,該鏈表的首元素是init_mm內存描述符,它代表init進程的地址空間殴胧。
物理內存是通過分頁機制實現(xiàn)的.
物理頁在系統(tǒng)中由也結構struct page描述渗稍,所有的page都存儲在數(shù)組mem_map[]中,可通過該數(shù)組找到系統(tǒng)中的每一頁团滥。
2) malloc 實現(xiàn)
如何實現(xiàn)一個malloc:CodingLabs - 如何實現(xiàn)一個malloc
上面的blog 推理非常清晰,struct僅僅加一個變量,變成下一種情況竿屹。圖畫的非常準確.
9 valgraind
內存問題分析的利器——valgraind的memcheck 內存問題分析的利器——valgrind的memcheck_方亮的專欄-CSDN博客
Valgrind使用簡介 Valgrind使用簡介_耿小渣的進階之路-CSDN博客_valgrind
10 內存分析命令
1) 概述
a) 內存指標概念
Item | 全稱 | 含義 | 等價 |
---|---|---|---|
USS | Unique Set Size | 物理內存 | 進程獨占的內存 |
PSS | Proportional Set Size | 物理內存 | PSS= USS+ 按比例包含共享庫 |
RSS | Resident Set Size | 物理內存 | RSS= USS+ 包含共享庫 |
VSS | Virtual Set Size | 虛擬內存 | VSS= RSS+ 未分配實際物理內存 |
故內存的大小關系:VSS >= RSS >= PSS >= USS
b) 內存分析命令
常用的內存調優(yōu)分析命令:dumpsys meminfo;procrank;cat /proc/meminfo;free;showmap;vmstat
小結
A 區(qū):虛實轉換; B 區(qū):Buddy伙伴系統(tǒng)和slab系統(tǒng); C 區(qū):內核空間分類; D 區(qū):單個進程的內存管理 task_struct 說明
頁表就是索引,伙伴系統(tǒng)就是內存池.
other: 內核用struct page結構體表示每個物理頁灸姊,struct page結構體占40個字節(jié).假定系統(tǒng)物理頁大小為4KB拱燃,對于4GB物理內存,1M個頁面力惯,故所有的頁面page結構體共占有內存大小為40MB.
用戶空間對應進程碗誉,所以當進程切換召嘶,用戶空間也會跟著變化;
內核空間是由內核負責映射哮缺,不會跟著進程變化弄跌;內核空間地址有自己對應的頁表,用戶進程各自有不同額頁表
都看到這里了尝苇,隨手點個贊唄,謝謝您!