GNU/Linux >> Linux の 問題 >  >> Linux

Java プロセスの常駐メモリ使用量 (RSS) の増加

私は同じ問題に遭遇しました。これは glibc>=2.10 の既知の問題です

解決策は、この環境変数 export MALLOC_ARENA_MAX=4 を設定することです

MALLOC_ARENA_MAX の設定に関する IBM の記事https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

Google で MALLOC_ARENA_MAX を検索するか、SO で検索して多くの参照を見つけてください。

割り当てられたメモリの断片化が少なくなるように最適化するために、他の malloc オプションも調整することをお勧めします。

# 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

また、ネイティブ メモリ リークが発生している可能性もあります。一般的な問題は、ZipInputStream を閉じないことによって引き起こされるネイティブ メモリ リークです。 /GZIPInputStream .

ZipInputStream の典型的な方法 Class.getResource の呼び出しによって開かれます /ClassLoader.getResource openConnection().getInputStream() を呼び出す java.net.URL で インスタンスまたは Class.getResourceAsStream を呼び出して /ClassLoader.getResourceAsStream .これらのストリームが常に閉じられるようにする必要があります。

一般的に使用されているオープン ソース ライブラリの一部には、クローズされていない状態でリークするバグがありました java.util.zip.Inflater または java.util.zip.Deflater インスタンス。たとえば、Nimbus Jose JWT ライブラリは、6.5.1 バージョンで関連するメモリ リークを修正しました。 Java JWT (jjwt) にも同様のバグがあり、バージョン 0.10.7 で修正されました。この 2 つのケースのバグ パターンは、DeflaterOutputStream.close() を呼び出すという事実でした。 と InflaterInputStream.close() Deflater.end() を呼び出さないでください /Inflater.end() Deflater の場合 /Inflater インスタンスが提供されます。そのような場合、閉じられているストリームのコードをチェックするだけでは十分ではありません。 Deflaterごと /Inflater コードで作成されたインスタンスには、その .end() を処理する必要があります 呼ばれます。

Zip*Stream リークをチェックする 1 つの方法は、ヒープ ダンプを取得し、名前に「zip」、「Inflater」、または「Deflater」を含むクラスのインスタンスを検索することです。これは、Yourkit Java Profiler、JProfiler、Eclipse MAT などの多くのヒープ ダンプ分析ツールで可能です。また、場合によってはファイナライズ後にのみメモリが解放されるため、ファイナライズ状態のオブジェクトをチェックすることも価値があります。ネイティブ ライブラリを使用している可能性のあるクラスをチェックすると便利です。これは TLS/ssl ライブラリにも当てはまります。

java.util.zip.Inflater のソースを見つけるために使用できる Java エージェントである Elastic の leakchecker と呼ばれる OSS ツールがあります。 閉じられていないインスタンス (.end() 呼び出されません)。

一般的なネイティブ メモリ リーク (zip ライブラリ リークだけでなく) の場合、MALLOC_CONF の設定を指定して malloc サンプリング プロファイリングを有効にすることで、jemalloc を使用してネイティブ メモリ リークをデバッグできます。 環境変数。詳細な手順については、このブログ投稿 (http://www.evanjones.ca/java-native-leak-bug.html) を参照してください。このブログ投稿には、jemalloc を使用して Java アプリケーションのネイティブ メモリ リークをデバッグする方法に関する情報も含まれています。 jemalloc を紹介し、Elastic がクローズされていない zip インフレータ リソースによって引き起こされる問題を追跡するためにオープンソース化したツール、leakchecker について言及している Elastic からのブログ投稿もあります。

ByteBuffers に関連するネイティブ メモリ リークに関するブログ投稿もあります。 Java 8u102 には、特別なシステム プロパティ jdk.nio.maxCachedBufferSize があります。 そのブログ投稿で説明されているキャッシュの問題を制限します。

-Djdk.nio.maxCachedBufferSize=262144

また、開いているファイル ハンドルを常にチェックして、大量の mmap:ed ファイルが原因でメモリ リークが発生しているかどうかを確認することもお勧めします。 Linux lsof の場合 開いているファイルと開いているソケットを一覧表示するために使用できます:

lsof -Pan -p PID

プロセスのメモリ マップのレポートは、ネイティブ メモリ リークの調査にも役立ちます

pmap -x PID

Docker で実行されている Java プロセスの場合、「ホスト」で lsof または pmap コマンドを実行できる必要があります。このコマンドでコンテナ化されたプロセスの PID を見つけることができます

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

また、スレッド ダンプを取得して (または jconsole/JMX を使用して) スレッドの数を確認することも役立ちます。これは、各スレッドがそのスタックに 1 MB のネイティブ メモリを消費するためです。多数のスレッドは大量のメモリを使用します。

JVM にはネイティブ メモリ トラッキング (NMT) もあります。これは、ネイティブ メモリを使い果たしているのが JVM 自体であるかどうかを確認するのに役立つ場合があります。

jattach ツールは、コンテナー化された (docker) 環境でも使用して、ホストからスレッドダンプまたはヒープダンプをトリガーできます。また、NMT の制御に必要な jcmd コマンドを実行することもできます。


Linux
  1. Linuxのメモリ使用量

  2. Linuxpmapコマンドでプロセスのメモリ使用量を確認する方法

  3. Linux –単一のLinuxプロセスのメモリ使用量を制限しますか?

  1. アプリケーションまたはプロセスの実際のメモリ使用量を測定するにはどうすればよいですか?

  2. Linux/Unix プロセスのピーク時のメモリ使用量

  3. Linuxで単一プロセスのCPU使用率とメモリ使用率を取得しますか?

  1. 1 つのプロセスのメモリ使用量を呼び出して追跡する

  2. 単一の Linux プロセスのメモリ使用量を制限する

  3. プロセスのピーク時のメモリ使用量