O Linux informa incorretamente o tamanho do processo com mapeamento múltiplo de heap

O Linux informa incorretamente o tamanho do processo com mapeamento múltiplo de heap

Existe esse problema no Linux quando um processo mapeia a mesma memória física para vários endereços de uma só vez ("multimapeamento de heap").

Por exemplo,Coletor de lixo ZGC do Javafaz isso.

Quando ocorre o mapeamento múltiplo de heap, o Linux (pelo menos as versões que uso) calcula mal (relata demais) o tamanho do processo residente. Isso afeta todos os programas principais que consultam o sistema operacional em busca de tamanhos de processos.

Na verdade, não tenho mais como saber quão grande é realmente um processo.

Esta captura de tela é o que é mostrado para um programa Java habilitado para ZGC com <<200 MB de objetos Java. Então, na realidade, o processo gira em torno de 500 MB, e não vários GB.

insira a descrição da imagem aqui

Então, para chegar à pergunta: alguém conhece uma versão do Linux (ou patch ou ferramenta) que possa relatar corretamente os tamanhos dos processos neste caso?

Editar:Agora eu fiz minha própria pequena ferramentaespecificamente para o caso de uso ZGC.

Responder1

Você pode perguntar ao kernel como o processo usa a memória ( /proc/PID/smaps) e então fazer as contas com base na memória compartilhada e privada relatada. A memória compartilhada só deve ser contada uma vez.

Abaixo está um código que analisa smaps e resume os vários tipos de uso de memória para uma lista de pids. A memória de tamanho de conjunto exclusivo (uss) é a memória privada do processo e pode dar uma ideia melhor sobre quanta memória o processo realmente usa. Em última análise, torna-se uma questão de como você gostaria de incluir a memória compartilhada na equação.

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

informação relacionada