Linux informa erróneamente el tamaño del proceso con mapeo múltiple del montón

Linux informa erróneamente el tamaño del proceso con mapeo múltiple del montón

Existe este problema en Linux cuando un proceso asigna la misma memoria física a varias direcciones a la vez ("asignación múltiple del montón").

Por ejemplo,Recolector de basura ZGC de JavaHaz esto.

Cuando ocurre el mapeo múltiple del montón, Linux (al menos las versiones que uso) calcula mal (sobreinforma) el tamaño del proceso residente. Esto afecta a la parte superior y a todos los programas que consultan el tamaño de los procesos en el sistema operativo.

En efecto, ya no tengo forma de saber qué tan grande es realmente un proceso.

Esta captura de pantalla es lo que se muestra arriba para un programa Java habilitado para ZGC con <<200 MB de objetos Java. Entonces, en realidad, el proceso ocupa alrededor de 500 MB, no varios GB.

ingrese la descripción de la imagen aquí

Entonces, para pasar a la pregunta: ¿Alguien conoce una versión (o parche o herramienta) de Linux que pueda informar correctamente los tamaños de proceso en este caso?

Editar:Ahora hice mi propia pequeña herramientaespecíficamente para el caso de uso ZGC.

Respuesta1

Podría preguntarle al kernel cómo usa el proceso la memoria ( /proc/PID/smaps) y luego hacer los cálculos basándose en la memoria compartida y privada informada. La memoria compartida sólo debe contarse una vez.

A continuación se muestra un código que analiza smaps y resume los distintos tipos de uso de memoria para obtener una lista de pids. La memoria de tamaño de conjunto único (uss) es la memoria privada del proceso y podría dar una mejor idea de cuánta memoria utiliza realmente el proceso. En última instancia, se convierte en una cuestión de cómo le gustaría incluir la memoria compartida en la ecuación.

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

información relacionada