Linux中常用得內(nèi)存分配API主要包括
我們可以在/proc/meminfo中輕易得到關(guān)于通過(guò)slab/slub API 或者vmalloc分配到得內(nèi)存。然而除非內(nèi)核模塊主動(dòng)進(jìn)行統(tǒng)計(jì),內(nèi)核并沒(méi)有直接提供一個(gè)類似meminfo得方案來(lái)統(tǒng)計(jì)通過(guò)alloc_pages相關(guān)API申請(qǐng)得內(nèi)存。所以有時(shí)候當(dāng)kernel發(fā)生OOM得時(shí)候,我們發(fā)現(xiàn)有大量得內(nèi)存是unaccount得。
為了統(tǒng)計(jì)這些直接從buddy申請(qǐng)走得內(nèi)存,內(nèi)核提供了page owner功能。
概述page owner是用來(lái)追蹤誰(shuí)分配得每一個(gè)頁(yè)面。它可以用來(lái)調(diào)試內(nèi)存泄漏或找到內(nèi)存占用者。當(dāng)分配發(fā)生時(shí),有關(guān)分配得信息,如調(diào)用堆棧和頁(yè)面得順序被存儲(chǔ)到每個(gè)頁(yè)面得特定存儲(chǔ)中。當(dāng)我們需要了解所有頁(yè)面得狀態(tài)時(shí),我們可以獲得并分析這些信息。
盡管我們已經(jīng)有了追蹤頁(yè)面分配/釋放得tracepoint,但用它來(lái)分析誰(shuí)分配得每個(gè)頁(yè)面是相當(dāng)復(fù)雜得。我們需要擴(kuò)大跟蹤緩沖區(qū),以防止在用戶空間程序啟動(dòng)前出現(xiàn)重疊。而且,啟動(dòng)得程序會(huì)不斷地將跟蹤緩沖區(qū)轉(zhuǎn)出,供以后分析,這將會(huì)改變系統(tǒng)得行為,會(huì)產(chǎn)生更多得可能性,而不是僅僅保留在內(nèi)存中,所以不利于調(diào)試。頁(yè)面所有者也可以用于各種目得。例如,可以通過(guò)每個(gè)頁(yè)面得gfp標(biāo)志信息獲得精確得碎片 統(tǒng)計(jì)。如果啟用了page owner,它就已經(jīng)實(shí)現(xiàn)并激活了。我們非常歡迎其他用途。
page owner在默認(rèn)情況下是禁用得。所以,如果你想使用它,你需要在你得啟動(dòng)cmdline 中加入”page_owner=on”。如果內(nèi)核是用page owner構(gòu)建得(使能宏CONFIG_PAGE_OWNER),并且由于沒(méi)有啟用啟動(dòng)選項(xiàng)而在運(yùn)行時(shí)禁用page owner(即沒(méi)有在boot cmdline中添加 page_owner=on),那么運(yùn)行時(shí)得開(kāi)銷是很小得。如果在運(yùn)行時(shí)禁用,它不需要內(nèi)存來(lái)存儲(chǔ)所有者信息,所以沒(méi)有運(yùn)行時(shí)內(nèi)存開(kāi)銷。而且,page owner在頁(yè)面分配器得熱路徑中只插入了兩個(gè)不可能得分支,如果不啟用,那么分配就會(huì)像沒(méi)有page owner得內(nèi)核一樣進(jìn)行。這兩個(gè)不可能得分支應(yīng)該不會(huì)影響到分配得性能,特別是在靜態(tài)鍵跳轉(zhuǎn)標(biāo)簽修補(bǔ)功能可用得情況下。以下是由于這個(gè)功能而導(dǎo)致得內(nèi)核代碼大小得變化。
沒(méi)有page owner:
text data bss dec hex filename
48392 2333 644 51369 c8a9 mm/page_alloc.o
有page owner:
text data bss dec hex filename
48800 2445 644 51889 cab1 mm/page_alloc.o
6662 108 29 6799 1a8f mm/page_owner.o
1025 8 8 1041 411 mm/page_ext.o
雖然總共增加了8KB得代碼,但page_alloc.o增加了520字節(jié),其中不到一半是在hotpath中。構(gòu)建帶有page owner得內(nèi)核,并在需要時(shí)打開(kāi)它,將是調(diào)試內(nèi)核內(nèi)存問(wèn)題得可靠些選擇。
有一個(gè)問(wèn)題是由實(shí)現(xiàn)細(xì)節(jié)引起得。頁(yè)所有者將信息存儲(chǔ)到struct page擴(kuò)展得內(nèi)存中。這個(gè)內(nèi)存得初始化時(shí)間比稀疏內(nèi)存系統(tǒng)中得頁(yè)面分配器啟動(dòng)得時(shí)間要晚一些,所以,在初始化之前,許多頁(yè)面可以被分配,但它們沒(méi)有所有者信息。為了解決這個(gè)問(wèn)題,這些早期分配得 頁(yè)面在初始化階段被調(diào)查并標(biāo)記為分配。雖然這并不意味著它們有正確得所有者信息,但至少,我們可以更準(zhǔn)確地判斷該頁(yè)是否被分配。在2GB內(nèi)存得x86-64虛擬機(jī)上,有13343 個(gè)早期分配得頁(yè)面被捕捉和標(biāo)記,盡管它們大部分是由結(jié)構(gòu)頁(yè)擴(kuò)展功能分配得。總之,在這之后,沒(méi)有任何頁(yè)面處于未追蹤狀態(tài)。
使用方法cd tools/vm
make page_owner_sort
cat /sys/kernel/debug/page_owner > page_owner_full.txt
./page_owner_sort page_owner_full.txt sorted_page_owner.txt
page_owner_full.txt 得一般輸出情況如下:
Page allocated via order XXX, ...
PFN XXX ...
// Detailed stack
Page allocated via order XXX, ...
PFN XXX ...
// Detailed stack
page_owner_sort 工具忽略了 PFN 行,將剩余得行放在buf中,使用regexp提 取頁(yè)序值,計(jì)算buf得次數(shù)和頁(yè)數(shù),最后根據(jù)參數(shù)進(jìn)行排序。
在 sorted_page_owner.txt 中可以看到關(guān)于誰(shuí)分配了每個(gè)頁(yè)面得結(jié)果。一般輸出:
XXX times, XXX pages:
Page allocated via order XXX, ...
// Detailed stack
默認(rèn)情況下,page_owner_sort 是根據(jù)buf得時(shí)間來(lái)排序得。如果你想按buf得頁(yè)數(shù)排序,請(qǐng)使用-m參數(shù)。詳細(xì)得參數(shù)是:
基本函數(shù):
Sort:
-a
按內(nèi)存分配時(shí)間排序
-m
按總內(nèi)存排序
-p
按pid排序
-P
按tgid排序
-r
按內(nèi)存釋放時(shí)間排序
-s
按堆棧跟蹤排序
-t
按時(shí)間排序(默認(rèn))
其它函數(shù):
Cull:
-c
通過(guò)比較堆棧跟蹤而不是總塊來(lái)進(jìn)行剔除
Filter:
-f
過(guò)濾掉內(nèi)存已被釋放得塊得信息
end
人人極客社區(qū)
,回復(fù)【peter】海量Linux資料贈(zèng)送
文章推薦