本文包括如下三部分:
- 基本介紹與輸出介紹
- 第一行基礎(chǔ)信息講解
- 詳細(xì)信息講解
3.1 Size
3.2 Rss
3.3 Pss、Shared/Private_Clean/Dirty
3.4 Referenced
3.5 Anonymous
3.6 ShmemPmdMapped
3.7 Shared/Private_Hugetlb
3.8 Swap
3.9 SwapPss
3.10 KernelPageSize、MMUPageSize
3.11 Locked
3.12 THPeligible
3.13 VmFlags
如果對(duì)Linux的內(nèi)存管理機(jī)制沒(méi)有了解過(guò),建議先了解一下,便于理解:Linux內(nèi)存管理
基本介紹
/proc/PID/smaps 文件是基于 /proc/PID/maps 的擴(kuò)展,他展示了一個(gè)進(jìn)程的內(nèi)存消耗,比同一目錄下的maps文件更為詳細(xì)。
值得說(shuō)明一下的是,每一個(gè)VMA(虛擬內(nèi)存區(qū)域,即一個(gè) vm_area_struct 結(jié)構(gòu)指向的內(nèi)存區(qū)域)都有如下的一系列數(shù)據(jù):
08048000-080bc000 r-xp 00000000 03:02 13130 /bin/bash
Size: 1084 kB
Rss: 892 kB
Pss: 374 kB
Shared_Clean: 892 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 892 kB
Anonymous: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw
第一行基礎(chǔ)信息
在講解字段含義之前,我們必須知道什么匿名映射:
在Linux 內(nèi)存管理的進(jìn)程用戶態(tài)內(nèi)存分布中提到過(guò),映射分為文件映射和匿名映射。
文件映射就是磁盤中的數(shù)據(jù)通過(guò)文件系統(tǒng)映射到內(nèi)存再通過(guò)文件映射映射到虛擬空間,這樣,用戶就可以在用戶空間通過(guò) open ,read, write 等函數(shù)區(qū)操作文件內(nèi)容。至于實(shí)際的代碼,open,read,write,close,mmap... 操作的虛擬地址都屬于文件映射。
匿名映射就是用戶空間需要分配一定的物理內(nèi)存來(lái)存儲(chǔ)數(shù)據(jù),這部分內(nèi)存不屬于任何文件,內(nèi)核就使用匿名映射將內(nèi)存中的某段物理地址與用戶空間一一映射,這樣用戶就可用直接操作虛擬地址來(lái)范圍這段物理內(nèi)存。比如使用malloc申請(qǐng)內(nèi)存。
- 08048000-080bc000 是該虛擬內(nèi)存段的開(kāi)始和結(jié)束位置
- r-xp 內(nèi)存段的權(quán)限,分別是可讀、可寫、可運(yùn)行、私有或共享,最后一位p代表私有,s代表共享
- 00000000 該虛擬內(nèi)存段起始地址在對(duì)應(yīng)的映射文件中以頁(yè)為單位的偏移量,對(duì)匿名映射,它等于0或者vm_start/PAGE_SIZE
- 03:02 文件的主設(shè)備號(hào)和次設(shè)備號(hào)。對(duì)匿名映射來(lái)說(shuō),因?yàn)闆](méi)有文件在磁盤上,所以沒(méi)有設(shè)備號(hào),始終為00:00。對(duì)有名映射來(lái)說(shuō),是映射的文件所在設(shè)備的設(shè)備號(hào)。
- 13130 被映射到虛擬內(nèi)存的文件的索引節(jié)點(diǎn)號(hào),通過(guò)該節(jié)點(diǎn)可以找到對(duì)應(yīng)的文件,對(duì)匿名映射來(lái)說(shuō),因?yàn)闆](méi)有文件在磁盤上,所以沒(méi)有節(jié)點(diǎn)號(hào),始終為00:00。
- /bin/bash 被映射到虛擬內(nèi)存的文件名稱。后面帶(deleted)的是內(nèi)存數(shù)據(jù),可以被銷毀。對(duì)有名來(lái)說(shuō),是映射的文件名。對(duì)匿名映射來(lái)說(shuō),是此段虛擬內(nèi)存在進(jìn)程中的角色。[stack]表示在進(jìn)程中作為棧使用,[heap]表示堆。其余情況則無(wú)顯示。
第一行的信息完全同于在maps文件中輸出的信息。對(duì)于不熟悉maps文件的讀者可以先了解maps的字段的含義與實(shí)現(xiàn)機(jī)制。
詳細(xì)信息
Size:虛擬內(nèi)存空間大小。但是這個(gè)內(nèi)存值不一定是物理內(nèi)存實(shí)際分配的大小,因?yàn)樵谟脩魬B(tài)上,虛擬內(nèi)存總是延遲分配的。這個(gè)值計(jì)算也非常簡(jiǎn)單,就是該VMA的開(kāi)始位置減結(jié)束位置。
延遲分配就是當(dāng)進(jìn)程申請(qǐng)內(nèi)存的時(shí)候,Linux會(huì)給他先分配頁(yè),但是并不會(huì)區(qū)建立頁(yè)與頁(yè)框的映射關(guān)系,意思就是說(shuō)并不會(huì)分配物理內(nèi)存,而當(dāng)真正使用的時(shí)候,就會(huì)產(chǎn)生一個(gè)缺頁(yè)異常,硬件跳轉(zhuǎn)page fault處理程序執(zhí)行,在其中分配物理內(nèi)存,然后修改頁(yè)表(創(chuàng)建頁(yè)表項(xiàng))。異常處理完畢,返回程序用戶態(tài),繼續(xù)執(zhí)行。
Rss:是實(shí)際分配的內(nèi)存,這部分物理內(nèi)存已經(jīng)分配,不需要缺頁(yè)中斷就可以使用的。
這里有一個(gè)公式計(jì)算Rss:
Rss=Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty
share/private:該頁(yè)面是共享還是私有。
dirty/clean:該頁(yè)面是否被修改過(guò),如果修改過(guò)(dirty),在頁(yè)面被淘汰的時(shí)候,就會(huì)把該臟頁(yè)面回寫到交換分區(qū)(換出,swap out)。有一個(gè)標(biāo)志位用于表示頁(yè)面是否dirty。
share/private_dirty/clean 計(jì)算邏輯:
查看該page的引用數(shù),如果引用>1,則歸為shared,如果是1,則歸為private,同時(shí)也查看該page的flag,是否標(biāo)記為_(kāi)PAGE_DIRTY,如果不是,則認(rèn)為干凈的。
Pss(proportional set size):是平攤計(jì)算后的實(shí)際物理使用內(nèi)存(有些內(nèi)存會(huì)和其他進(jìn)程共享,例如mmap進(jìn)來(lái)的)。實(shí)際上包含下面private_clean+private_dirty,和按比例均分的shared_clean、shared_dirty。
舉個(gè)計(jì)算Pss的例子:
如果進(jìn)程A有x個(gè)private_clean頁(yè)面,有y個(gè)private_dirty頁(yè)面,有z個(gè)shared_clean僅和進(jìn)程B共享,有h個(gè)shared_dirty頁(yè)面和進(jìn)程B、C共享。那么進(jìn)程A的Pss為:
x + y + z/2 + h/3
Referenced:當(dāng)前頁(yè)面被標(biāo)記為已引用或者包含匿名映射(The amount of memory currently marked as referenced or a mapping associated with a file may contain anonymous pages)。
在Linux內(nèi)存管理的頁(yè)面替換算法里講過(guò),當(dāng)某個(gè)頁(yè)面被訪問(wèn)后,Referenced標(biāo)志被設(shè)置,如果該標(biāo)志設(shè)置了,就 不能將該頁(yè)移出。
Anonymous:匿名映射的物理內(nèi)存,這部分內(nèi)存不來(lái)自于文件的內(nèi)存大小。
ShmemPmdMapped:PMD頁(yè)面已經(jīng)被映射的共享(shmem / tmpfs)內(nèi)存量。在官方文檔中,這樣解釋:"ShmemPmdMapped" shows the ammount of shared (shmem/tmpfs) memory backed by huge pages.
Shared/Private_Hugetlb:由hugetlbfs頁(yè)面支持的內(nèi)存使用量,由于歷史原因,該頁(yè)面未計(jì)入“ RSS”或“ PSS”字段中。 并且這些沒(méi)有包含在Shared/Private_Clean/Dirty 字段中。
Swap:存在于交換分區(qū)的數(shù)據(jù)大小(如果物理內(nèi)存有限,可能存在一部分在主存一部分在交換分區(qū))
SwapPss:這個(gè)我并沒(méi)有找到對(duì)應(yīng)解釋,但從源碼可以得知,計(jì)算邏輯就跟pss一樣,只不過(guò)針對(duì)的是交換分區(qū)的內(nèi)存。
static void smaps_pte_entry(pte_t *pte, unsigned long addr,
struct mm_walk *walk)
{
struct mem_size_stats *mss = walk->private;
struct vm_area_struct *vma = walk->vma;
struct page *page = NULL;
if (pte_present(*pte)) {//----------------------------------頁(yè)面在內(nèi)存中
page = vm_normal_page(vma, addr, *pte);
} else if (is_swap_pte(*pte)) {//---------------------------頁(yè)面被swap出
swp_entry_t swpent = pte_to_swp_entry(*pte);
if (!non_swap_entry(swpent)) {
int mapcount;
mss->swap += PAGE_SIZE;
mapcount = swp_swapcount(swpent);
if (mapcount >= 2) {
u64 pss_delta = (u64)PAGE_SIZE << PSS_SHIFT;
do_div(pss_delta, mapcount);
mss->swap_pss += pss_delta; // --------- 如果引用超過(guò)1,就將均值加入swap_pss中
} else {
mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT;// ------------ 直接加一個(gè)頁(yè)大小
}
} else if (is_migration_entry(swpent))
page = migration_entry_to_page(swpent);
}
if (!page)//----------------------------------------------如果頁(yè)面不存在,就不用更新mss其他信息了;如果存在,調(diào)用smaps_account()更新mss。
return;
smaps_account(mss, page, PAGE_SIZE, pte_young(*pte), pte_dirty(*pte));
}
KernelPageSize:內(nèi)核一頁(yè)的大小
MMUPageSize:MMU頁(yè)大小,大多數(shù)情況下,和KernelPageSize大小一樣。
Locked:常駐物理內(nèi)存的大小,這些頁(yè)不會(huì)被換出。
THPeligible:映射是否符合分配THP的條件。如果為true,則為1,否則為0。 它僅顯示當(dāng)前狀態(tài)。
THP,透明大頁(yè)(Transparent Huge Pages),RHEL 6 開(kāi)始引入,目的是使用更大的內(nèi)存頁(yè)面(memory page size) 以適應(yīng)越來(lái)越大的系統(tǒng)內(nèi)存,讓操作系統(tǒng)可以支持現(xiàn)代硬件架構(gòu)的大頁(yè)面容量功能。與標(biāo)準(zhǔn)大頁(yè)的區(qū)別在于分配機(jī)制,標(biāo)準(zhǔn)大頁(yè)管理是預(yù)分配的方式,而透明大頁(yè)管理則是動(dòng)態(tài)分配的方式。
VmFlags:表示與特定虛擬內(nèi)存區(qū)域關(guān)聯(lián)的內(nèi)核標(biāo)志。標(biāo)志如下:
rd - readable
wr - writeable
ex - executable
sh - shared
mr - may read
mw - may write
me - may execute
ms - may share
gd - stack segment growns down
pf - pure PFN range
dw - disabled write to the mapped file
lo - pages are locked in memory
io - memory mapped I/O area
sr - sequential read advise provided
rr - random read advise provided
dc - do not copy area on fork
de - do not expand area on remapping
ac - area is accountable
nr - swap space is not reserved for the area
ht - area uses huge tlb pages
ar - architecture specific flag
dd - do not include area into core dump
sd - soft-dirty flag
mm - mixed map area
hg - huge page advise flag
nh - no-huge page advise flag
mg - mergable advise flag
參考文章:
Linux官方文檔
Linux smaps接口文件結(jié)構(gòu)
linux proc maps文件分析
linux proc maps文件分析
匿名文件映射問(wèn)題 (概念不清晰)
Linux中各種設(shè)備及設(shè)備號(hào)
Linux smaps接口文件結(jié)構(gòu)
閑聊Linux內(nèi)存管理(1)
Linux物理內(nèi)存回收機(jī)制
Linux /proc/$pid/smaps的含義
Linux傳統(tǒng)Huge Pages與Transparent Huge Pages再次學(xué)習(xí)總結(jié)
Linux內(nèi)存管理 一個(gè)進(jìn)程究竟占用多少空間?-VSS/RSS/PSS/USS
linux 內(nèi)存查看方法:meminfo\maps\smaps\status 文件解析