GNU/Linux >> Linux Esercitazione >  >> Linux

Crescente utilizzo della memoria residente (RSS) di Java Process

Mi sono imbattuto nello stesso problema. Questo è un problema noto con glibc>=2.10

La cura è impostare questa variabile env export MALLOC_ARENA_MAX=4

Articolo IBM sull'impostazione di MALLOC_ARENA_MAXhttps://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

Google per MALLOC_ARENA_MAX o cercalo su SO per trovare molti riferimenti.

Potresti voler mettere a punto anche altre opzioni malloc per ottimizzare la bassa frammentazione della memoria allocata:

# tune glibc memory allocation, optimize for low fragmentation
# limit the number of arenas
export MALLOC_ARENA_MAX=2
# disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt"
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536

È anche possibile che ci sia una perdita di memoria nativa. Un problema comune sono le perdite di memoria nativa causate dalla mancata chiusura di un ZipInputStream /GZIPInputStream .

Un modo tipico in cui un ZipInputStream viene aperto tramite una chiamata a Class.getResource /ClassLoader.getResource e chiamando openConnection().getInputStream() sul java.net.URL istanza o chiamando Class.getResourceAsStream /ClassLoader.getResourceAsStream . Bisogna assicurarsi che questi flussi vengano sempre chiusi.

Alcune librerie open source di uso comune hanno avuto bug che trapelano java.util.zip.Inflater non chiusi o java.util.zip.Deflater istanze. Ad esempio, la libreria Nimbus Jose JWT ha risolto una perdita di memoria correlata nella versione 6.5.1. Java JWT (jjwt) aveva un bug simile che è stato corretto nella versione 0.10.7. Il modello di bug in questi 2 casi era il fatto che le chiamate a DeflaterOutputStream.close() e InflaterInputStream.close() non chiamare Deflater.end() /Inflater.end() quando un Deflater /Inflater istanza è fornita. In questi casi, non è sufficiente controllare il codice per la chiusura dei flussi. Ogni Deflater /Inflater le istanze create nel codice devono avere la gestione di quel .end() viene chiamato.

Un modo per verificare la presenza di perdite Zip*Stream è ottenere un dump dell'heap e cercare istanze di qualsiasi classe con "zip", "Inflater" o "Deflater" nel nome. Ciò è possibile in molti strumenti di analisi dell'heap dump come Yourkit Java Profiler, JProfiler o Eclipse MAT. Vale anche la pena controllare gli oggetti nello stato di finalizzazione poiché in alcuni casi la memoria viene rilasciata solo dopo la finalizzazione. È utile verificare la presenza di classi che potrebbero utilizzare librerie native. Questo vale anche per le librerie TLS/ssl.

Esiste uno strumento OSS chiamato leakchecker di Elastic che è un agente Java che può essere utilizzato per trovare le fonti di java.util.zip.Inflater istanze che non sono state chiuse (.end() non chiamato).

Per le perdite di memoria nativa in generale (non solo per le perdite di libreria zip), puoi utilizzare jemalloc per eseguire il debug delle perdite di memoria nativa abilitando il profilo di campionamento malloc specificando le impostazioni in MALLOC_CONF variabile d'ambiente. Istruzioni dettagliate sono disponibili in questo post del blog:http://www.evanjones.ca/java-native-leak-bug.html . Questo post del blog contiene anche informazioni sull'utilizzo di jemalloc per eseguire il debug di una perdita di memoria nativa nelle applicazioni Java. C'è anche un post sul blog di Elastic che parla di jemalloc e menziona leakchecker, lo strumento che Elastic ha reso opensource per rintracciare i problemi causati da risorse zip inflater non chiuse.

C'è anche un post sul blog su una perdita di memoria nativa relativa a ByteBuffers. Java 8u102 ha una proprietà di sistema speciale jdk.nio.maxCachedBufferSize per limitare il problema della cache descritto in quel post del blog.

-Djdk.nio.maxCachedBufferSize=262144

È anche utile controllare sempre gli handle di file aperti per vedere se la perdita di memoria è causata da una grande quantità di file mmap:ed. Su Linux lsof può essere usato per elencare file aperti e socket aperti:

lsof -Pan -p PID

Il report della mappa di memoria del processo potrebbe anche aiutare a indagare sulle perdite di memoria nativa

pmap -x PID

Per i processi Java in esecuzione in Docker, dovrebbe essere possibile eseguire il comando lsof o pmap sull'"host". Puoi trovare il PID del processo containerizzato con questo comando

docker inspect --format '{{.State.Pid}}' container_id

È anche utile ottenere un thread dump (o utilizzare jconsole/JMX) per verificare il numero di thread poiché ogni thread consuma 1 MB di memoria nativa per il proprio stack. Un gran numero di thread userebbe molta memoria.

C'è anche il Native Memory Tracking (NMT) nella JVM. Ciò potrebbe essere utile per verificare se è la JVM stessa a utilizzare la memoria nativa.

Lo strumento jattach può essere utilizzato anche in un ambiente containerizzato (docker) per attivare threaddump o heapdump dall'host. È anche in grado di eseguire comandi jcmd necessari per controllare NMT.


Linux
  1. Utilizzo della memoria di Linux

  2. Come controllare l'utilizzo della memoria del processo con il comando pmap di Linux

  3. Quando un processo esegue il fork, viene copiata la sua memoria virtuale o residente?

  4. Utilizzo elevato della memoria ma nessun processo lo sta utilizzando

  5. Ubuntu Linux:elabora la memoria di scambio e l'utilizzo della memoria

Strumento che consente la registrazione dell'utilizzo della memoria?

Linux – Hai bisogno di una spiegazione sulla dimensione del set residente/dimensione virtuale?

Picco di utilizzo della memoria di un processo Linux/Unix

Utilizzo della memoria del processo corrente in C

Richiama e monitora l'utilizzo della memoria di un processo

Determinazione corretta dell'utilizzo della memoria in Linux