您好,登錄后才能下訂單哦!
內核和處理器負責將虛擬內存映射到物理內存。為了提高效率,會在稱為頁面的內存組中創建內存映射,其中每個頁面的大小是處理器的詳細信息。盡管大多數處理器也支持更大的容量,但通常有4 KB,Linux稱其為 hugepage大頁面。內核可以從其自己的空閑列表中為物理內存頁面請求提供服務,內核為每個DRAM組和CPU維護這些請求以提高效率。內核自己的軟件也通常通過內核分配器(例如slab分配器)從這些空閑列表中消耗內存。
內存頁和交換
典型的用戶內存頁面的生命周期如圖7-2所示,其中列舉了以下步驟:
1. 應用程序從內存分配請求開始(例如,libc malloc() )。
2. 分配庫可以從其自己的空閑列表中為內存請求提供服務,或者它可能需要擴展虛擬內存來容納。根據分配庫,它將:
1. 通過調用brk() syscall并將堆內存用于分配來擴展堆的大小。
2. 通過mmap() 系統調用創建一個新的內存段。
3. 稍后,應用程序嘗試通過存儲和加載指令使用分配的內存范圍,這涉及調用處理器內存管理單元(MMU)進行虛擬到物理地址的轉換。至此,虛擬內存的謊言就暴露出來了:該地址沒有映射!這會導致稱為頁面錯誤的MMU錯誤。
4. 頁面錯誤由內核處理,內核建立從其物理內存可用列表到虛擬內存的映射,然后將該映射通知MMU以供以后查找。現在,該過程占用了額外的物理內存頁面。進程使用的物理內存量稱為其駐留集大小(RSS)。
5. 當系統上的內存需求過多時,內核頁面輸出守護程序(kswapd)可能會尋找可用的內存頁面。它將釋放三種類型的內存中的一種(盡管只有(c)如圖7-2所示,因為它顯示了用戶內存頁面的生命周期):
1. 從磁盤讀取但未修改的文件系統頁面(稱為“由磁盤支持”):可以立即釋放這些頁面,并在需要時簡單地重新讀取。這些頁面是應用程序可執行的文本,數據和文件系統元數據。
2. 已修改的文件系統頁面:這些是“臟”的,必須先寫入磁盤,然后才能釋放它們。
3. 應用程序內存頁面:由于它們沒有文件來源,因此被稱為匿名內存。如果正在使用交換設備,則可以先將它們存儲在交換設備上來釋放它們。將頁面寫到交換設備稱為交換(在Linux上)。
內存分配請求通常是頻繁的活動:對于繁忙的應用程序,用戶級別的分配每秒可能發生數百萬次。加載和存儲指令以及MMU查找更加頻繁。它們每秒可能發生數十億次。在圖7-2中,這些箭頭以粗體顯示。其他活動相對較少:brk()和mmap()調用,頁面錯誤和頁面退出(較亮的箭頭)。
page-out daemon頁面輸出守護程序
定期激活頁面輸出守護程序(kswapd)以掃描非活動和活動頁面的LRU列表,以尋找可用的內存。如圖7-3所示,當空閑內存越過低閾值時它將被喚醒,而當空閑內存越過高閾值時將回到睡眠狀態。
kswapd協調后臺頁面調出;除了CPU和磁盤I/O爭用外,這些不應直接損害應用程序性能。如果kswapd無法足夠快地釋放內存,則會超過可調的最小頁面閾值,并使用直接回收;這是釋放內存以滿足分配條件的前臺模式。在這種模式下,分配阻塞(停頓)并同步等待頁面被釋放。
直接回收可以調用內核模塊收縮器函數:這些釋放的內存可能保留在緩存中的內存,包括內核slab緩存。
swap devices交換設備
交換設備為內存不足的系統提供了降級的操作模式:進程可以繼續分配,但是現在將不常使用的頁面移入和移出交換設備,這通常會使應用程序運行得慢得多。
一些生產系統無需交換即可運行;這樣做的理由是,對于那些關鍵系統來說,降級的操作模式是永遠無法接受的,因為這些關鍵系統可能有許多冗余(且運行狀況良好)服務器,比開始交換的服務器要好用得多。(例如,對于Netflix云實例,通常就是這種情況。)
如果無交換系統的內存不足,則內核oom killer會犧牲一個進程。為了避免這種情況,將應用程序配置為永不超過系統的內存限制。
oom killer
Linux內存不足殺手是釋放內存的最后手段:它將使用啟發式方法找到受害者進程,并通過殺死它們來犧牲它們。啟發式尋找將釋放許多頁面的最大受害者,并且這不是關鍵任務,例如內核線程或init(PID 1)。Linux提供了在整個系統和每個進程中調整OOM殺手的行為的方法。
page compaction頁面壓縮
隨著時間的流逝,釋放的頁面變得碎片化,從而使內核很難根據需要分配較大的連續塊。內核使用壓縮程序來移動頁面,從而釋放連續區域。
file system caching and buffering文件系統緩存和緩沖
Linux借用空閑內存進行文件系統緩存,并在有需求時將其恢復為空閑狀態。這種借用的結果是,在Linux啟動之后,系統報告的可用內存趨向于零,這可能使用戶擔心系統實際上只是在預熱其文件系統緩存時會耗盡內存。此外,文件系統使用內存進行回寫緩沖(write-back buffering)。
可以將Linux調整為更喜歡從文件系統緩存中釋放或通過交換釋放內存(通過調整參數vm.swappiness)。
傳統的分析工具
傳統的性能工具提供了許多基于容量的內存使用情況統計信息,包括每個進程和系統范圍內使用了多少虛擬和物理內存,以及某些細分,例如按流程段或面板。分析內存使用率超出基本知識,例如頁面錯誤率,分配庫,運行時或應用程序對每個分配都需要內置的工具;或者可以使用像Valgrind這樣的虛擬機分析器;后一種方法可能會導致目標應用程序在檢測時運行速度慢10倍以上。BPF工具效率更高,開銷也更小。
Tool | Type | Description |
dmesg | Kernel log | OOM killer event details |
swapon | Kernel statistics | Swap device usage |
free | Kernel statistics | System-wide memory usage |
ps | Kernel statistics | Process statistics, including memory usage |
pmap | Kernel statistics | Process memory usage by segment |
vmstat | Kernel statistics | Various statistics, including memory |
sar | Kernel statistics | Can show page fault and page scanner rates |
perf | Software events, hardware statistics, hardware sampling | Memory-related PMC statistics and event sampling |
用于內存分析相關的BPF工具
內存相關的工具:
Tool | Source | Target | Description |
oomkill | BCC/BT | OOM | Shows extra info on OOM kill events 顯示oom相關的事件 |
memleak | BCC | Sched | Shows possible memory leak code paths 顯示可能的內存泄漏代碼路徑 |
mmapsnoop | Book | Syscalls | Traces mmap(2) calls system-wide 跟蹤系統范圍內的mmap調用 |
brkstack | Book | Syscalls | Shows brk() calls with user stack traces 顯示帶有用戶堆棧跟蹤的brk()調用 |
shmsnoop | BCC | Syscalls | Traces shared memory calls with details 跟蹤共享內存調用的詳細信息 |
faults | Book | Faults | Shows page faults, by user stack trace 通過用戶堆棧跟蹤顯示頁面錯誤 |
ffaults | Book | Faults | Shows page faults, by filename 通過文件名顯示頁面錯誤 |
vmscan | Book | VM | Measures VM scanner shrink and reclaim times 測量vm scaner的收縮和回收時間 |
drsnoop | BCC | VM | Traces direct reclaim events, showing latency 跟蹤直接回收事件,顯示延遲 |
swapin | Book | VM | Shows swap-ins by process 按進程顯示swap情況 |
hfaults | Book | Faults | Shows huge page faults, by process 按進程顯示巨頁錯誤情況 |
此外,還有幾個用于內存分析的BPF工具: kmem 、kpages 、 slabratetop 、 numamove
oomkill是一個BCC和bpftrace工具,用于跟蹤內存不足殺手事件并打印詳細信息(例如平均負載)。平均負載為OOM時的系統狀態提供了一些額外的上下文,顯示了系統是否正在變得忙碌或穩定。
此輸出表明PID 18601(perl)需要內存,這觸發了PID 1165(java)的OOM終止。PID 1165的內存占用已達到18006224個pages;這些通常每頁4 KB,具體取決于處理器和進程內存設置。loadavg平均負載表明,在OOM終止時,系統變得更加繁忙。
該工具通過使用kprobes跟蹤oom_kill_process() 函數并打印各種細節來工作。在這種情況下,只需讀取/proc/loadavg即可獲取平均負載。調試OOM事件時,可以根據需要增強此工具以打印其他詳細信息。此外,此工具尚未使用可以顯示有關如何選擇任務的更多詳細信息的oom跟蹤點。
memleak是一個BCC工具,可跟蹤內存分配和空閑事件以及分配堆棧跟蹤。隨著時間的流逝,它可以顯示長期幸存者-尚未釋放的分配。
此示例顯示了在bash shell進程上運行的memleak:
僅memleak不能告訴您這些分配是否是真正的內存泄漏(內存泄漏:指的是沒有引用并且永遠不會釋放的已分配內存),內存增長還是長期分配。為了區分它們,需要研究和理解代碼路徑。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。