Linux 使用堆多重映射错误报告进程大小

Linux 使用堆多重映射错误报告进程大小

当 Linux 中的一个进程同时将同一物理内存映射到多个地址(“堆多重映射”)时,就会出现这个问题。

例如,Java 的 ZGC 垃圾收集器做这个。

当发生堆多重映射时,Linux(至少是我使用的版本)会错误计算(高估)驻留进程大小。这会影响 top 以及所有向操作系统查询进程大小的程序。

实际上,我无法再知道一个过程到底有多大。

此屏幕截图显示了启用了 ZGC 的 Java 程序,其中 Java 对象小于 200 MB。因此,实际上,该进程大约为 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

相关内容