Linux неверно сообщает размер процесса при множественном отображении кучи

Linux неверно сообщает размер процесса при множественном отображении кучи

Эта проблема возникает в Linux, когда процесс отображает одну и ту же физическую память на несколько адресов одновременно («множественное отображение кучи»).

Например,Сборщик мусора ZGC в JavaОзначает ли это.

Когда происходит мульти-отображение кучи, Linux (по крайней мере, версии, которые я использую) неправильно вычисляет (завышает) размер резидентного процесса. Это влияет на top и все программы, которые запрашивают у ОС размеры процессов.

По сути, у меня больше нет возможности узнать, насколько масштабным является процесс.

Этот снимок экрана — то, что top показывает для программы Java с поддержкой ZGC с <<200 МБ объектов Java. Так что на самом деле процесс занимает около 500 МБ, а не несколько ГБ.

введите описание изображения здесь

Итак, перейдем к вопросу: знает ли кто-нибудь версию Linux (или патч, или инструмент), которая может правильно сообщать размеры процессов в этом случае?

Редактировать:Теперь я сделал свой собственный маленький инструмент.специально для варианта использования ZGC.

решение1

Вы можете спросить ядро ​​о том, как процесс использует память ( /proc/PID/smaps), а затем выполнить расчеты на основе сообщенной общей и частной памяти. Общая память должна быть учтена только один раз.

Ниже приведен код, который анализирует 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

Связанный контент