Linux はヒープ マルチマッピングでプロセス サイズを誤って報告する

Linux はヒープ マルチマッピングでプロセス サイズを誤って報告する

Linux では、プロセスが同じ物理メモリを一度に複数のアドレスにマップする場合 (「ヒープ マルチマッピング」)、この問題が発生します。

例えば、Java の ZGC ガベージ コレクターこれを行います。

ヒープ マルチマッピングが発生すると、Linux (少なくとも私が使用しているバージョン) は常駐プロセス サイズを誤って計算 (過剰報告) します。これは、top および OS にプロセス サイズを問い合わせるすべてのプログラムに影響します。

実際のところ、プロセスが実際にどれほど大きいかを知る方法がもうありません。

このスクリーンショットは、<<200 MB の Java オブジェクトを持つ ZGC 対応 Java プログラムについて top が表示したものです。したがって、実際にはプロセスは数 GB ではなく、約 500 MB です。

ここに画像の説明を入力してください

それで、質問に移ります。この場合、プロセス サイズを正しく報告できる Linux バージョン (またはパッチやツール) を知っている人はいますか?

編集:私は今、自分の小さなツールを作りました特に ZGC ユースケース向けです。

答え1

プロセスがメモリをどのように使用しているかをカーネルに問い合わせて ( /proc/PID/smaps)、報告された共有メモリとプライベート メモリに基づいて計算を行うことができます。共有メモリは 1 回だけカウントする必要があります。

以下は、smaps を解析し、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

関連情報