Linux 透過堆疊多重映射誤報進程大小

Linux 透過堆疊多重映射誤報進程大小

當一個進程同時將相同實體記憶體對應到多個位址(「堆多重映射」)時,Linux 中會出現此問題。

例如,Java的ZGC垃圾收集器做這個。

當發生堆疊多重映射時,Linux(至少是我使用的版本)會錯誤計算(過度報告)駐留進程大小。這會影響查詢作業系統進程大小的頂級程式和所有程式。

實際上,我無法知道一個過程實際上有多大。

此螢幕截圖是頂部顯示的具有 <<200 MB Java 物件的啟用 ZGC 的 Java 程式。所以實際上,該進程的大小約為 500 MB,而不是幾 GB。

在此輸入影像描述

那麼,回答這個問題:有誰知道在這種情況下可以正確報告進程大小的 Linux 版本(或修補程式或工具)?

編輯:我現在製作了自己的小工具專門針對 ZGC 用例。

答案1

您可以向核心詢問進程如何使用記憶體(/proc/PID/smaps),然後根據報告的共享記憶體和私有記憶體進行數學計算。共享記憶體只能計算一次。

以下是一些程式碼,用於解析 smap 並總結 pid 列表的各種類型的記憶體使用情況。唯一設定大小 (uss) 內存是進程的私有內存,可以更好地了解進程實際使用的內存量。最終,問題變成瞭如何將共享記憶體納入等式中。

rss = '.+?Rss:\s+(\d+)'
pss = '.+?Pss:\s+(\d+)'
shared_clean = '.+?Shared_Clean:\s+(\d+)'
shared_dirty = '.+?Shared_Dirty:\s+(\d+)'
priv_clean = '.+?Private_Clean:\s+(\d+)'
priv_dirty = '.+?Private_Dirty:\s+(\d+)'
MEM_REGEXP = /#{rss}#{pss}#{shared_clean}#{shared_dirty}#{priv_clean}#{priv_dirty}/m

def self.get_memory_map( pids)

    memory_map = {}
    #memory_map[ :pids_searched] = pids
    memory_map[ :pids_found] = {}
    memory_map[ :rss] = 0
    memory_map[ :pss] = 0
    memory_map[ :shared_clean] = 0
    memory_map[ :shared_dirty] = 0
    memory_map[ :rss_shared] = 0
    memory_map[ :priv_clean] = 0
    memory_map[ :priv_dirty] = 0
    memory_map[ :uss] = 0

    pids.each do |pid|
        begin
            # We don't want to see any "/proc/9723: No such file or directory" messages in stderr
            lines = nil
            Util.silently { lines = File.read( "/proc/#{pid}/smaps") }
        rescue
            lines = nil
        end
        if lines
            lines.scan(MEM_REGEXP) do |rss,pss,shared_clean,shared_dirty,priv_clean,priv_dirty|
                memory_map[ :pids_found][pid] = true
                memory_map[ :rss] += rss.to_i
                memory_map[ :pss] += pss.to_i
                memory_map[ :shared_clean] += shared_clean.to_i
                memory_map[ :shared_dirty] += shared_dirty.to_i
                memory_map[ :rss_shared] += shared_clean.to_i + shared_dirty.to_i
                memory_map[ :priv_clean] += priv_clean.to_i
                memory_map[ :priv_dirty] += priv_dirty.to_i
                memory_map[ :uss] += priv_clean.to_i + priv_dirty.to_i
            end
        end
    end
    memory_map[ :pids_found] = memory_map[ :pids_found].keys
    return memory_map
end

相關內容