Эта проблема возникает в 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