Dieses Problem tritt unter Linux auf, wenn ein Prozess denselben physischen Speicher gleichzeitig mehreren Adressen zuordnet („Heap-Multi-Mapping“).
Zum Beispiel,Javas ZGC-Garbage Collectormacht dies.
Wenn Heap-Multimapping auftritt, berechnet Linux (zumindest die von mir verwendeten Versionen) die Größe des residenten Prozesses falsch (überhöht). Dies betrifft top und alle Programme, die das Betriebssystem nach Prozessgrößen abfragen.
Tatsächlich habe ich keine Möglichkeit mehr, zu erfahren, wie groß ein Prozess tatsächlich ist.
Dieser Screenshot zeigt ein ZGC-fähiges Java-Programm mit <<200 MB an Java-Objekten. In Wirklichkeit ist der Prozess also etwa 500 MB groß, nicht mehrere GB.
Kommen wir also zur Frage: Kennt jemand eine Linux-Version (oder einen Patch oder ein Tool), die in diesem Fall die Prozessgrößen korrekt melden kann?
Bearbeiten:Ich habe jetzt mein eigenes kleines Werkzeug gemachtspeziell für den ZGC-Anwendungsfall.
Antwort1
Sie können den Kernel fragen, wie der Prozess den Speicher nutzt ( /proc/PID/smaps
) und dann die Berechnung auf Grundlage des gemeldeten gemeinsam genutzten und privaten Speichers durchführen. Der gemeinsam genutzte Speicher darf nur einmal gezählt werden.
Unten sehen Sie Code, der Smaps analysiert und die verschiedenen Arten der Speichernutzung für eine Liste von PIDs zusammenfasst. Der Unique Set Size (USS)-Speicher ist der private Speicher des Prozesses und könnte eine bessere Vorstellung davon vermitteln, wie viel Speicher der Prozess tatsächlich nutzt. Letztendlich ist es eine Frage, wie Sie den gemeinsam genutzten Speicher in die Gleichung einbeziehen möchten.
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