広く展開されているアプリケーションがあります (数百のワークステーションで実行されています)。1 つのサイト (および 1 つのサイトのみ - 当社の製品は多くの環境に広く展開されています) で、ランダムに次のエラーが発生します。
java.lang.OutOfMemoryError: java.lang.Thread.start0 (ネイティブ メソッド) で新しいネイティブ スレッドを作成できません (ソース不明)
オペレーティング システムは Windows 7 64 ビットです 32 ビット JVM (1.7.0_45) で実行しています
Windows タスク マネージャーを使用すると、プロセスに 39 個のネイティブ スレッドがあることがわかります (それほど多くはありません)。そのため、アプリでスレッド リークは発生していません...多くのスレッドを消費する他のプロセスはありません (エクスプローラーには 35 個のスレッドがあります)。 jvisualvm は 24、iexplore は 20、... 正確な数はわかりませんが、ユーザーの合計でおそらく300 スレッドを見ていると思われます)。
JVisualVM をアタッチしようとしましたが、プロセスへの接続に失敗しました (おそらくスレッドの枯渇の b/c)。しかし、JVisualVM から取得できるメトリクスによると、Java スレッドの数は約 22 のライブと 11 のデーモンです。
ヒープの動作は良好です。ヒープは 500MB で、実際には 250MB が使用されています。
プロセスは -Xmx512m で起動されます
私たちのプロセスは、597,744K のメモリ使用量 (タスク マネージャーで) を示しています。
ワークステーションには 8 GB の RAM があり、そのうち 3.8 ~ 4.0 GB しか使用されていません (32 ビット プロセスがそのすべてにアクセスするわけではありませんが、まだ十分に余裕があります)。
VMMap を使用し、スタックは 49,920KB のサイズで、2,284K がコミットされています。
プロセスは 5358KB の空き容量を示しており、空きリスト内の割り当て可能な最大ブロックのサイズは 1,024K です。
リソース モニターを使用したところ、コミット (KB) が 630428、ワーキング セット (KB) が 676,996、共有可能 (KB) が 79,252、プライベート (KB) が 597,744 と表示されました。
ここで何が起こっているのか、私は完全に途方に暮れています。私はこれに関する記事をたくさん読みましたが、一部の Linux システムでは、問題を引き起こす可能性のあるユーザーごとのスレッド制限があるようです (ただし、これは Linux ではなく、他の記事で説明されている問題は通常、必要性について語っています)。何千ものスレッド - ここでは間違いなくそうではありません)。
ヒープが非常に大きい場合、スレッドに使用できるスペースを食い尽くすことがわかりましたが、500MB は非常に合理的で小さなヒープのように見えます (特に 8GB RAM を搭載したワークステーションの場合)。
それで、私が知っていることはほとんどすべて使い果たしました - ここで何が起こっているのかについて、誰か追加の指針がありますか?
編集1:
この興味深い記事を見つけました: Eclipse が「新しいネイティブ スレッドを作成できません」でクラッシュする - 何かアイデアはありますか? (私の設定と情報は中)
彼らは、スタックサイズが問題になる可能性があることを示唆しています。
この記事: Sun/Oracle JVM のデフォルトの XSS 値はどこで確認できますか? - デフォルトのスタック サイズが 512KB であることを示す Oracle ドキュメントへのリンクを提供します。したがって、アプリに約 40 のスレッドがある場合、20 MB のスタックが表示されます。500MB ヒープ。これはすべて、32 ビット Java プロセスの通常の範囲内にあるようです。
したがって、私が考えることができる2つの可能性が残ります。
- 一時的な状態により、膨大な数のスレッドが作成されています (ただし、これらのスレッドは、診断を行う前に破棄されます)。
- メモリのセグメンテーションは、何らかの理由で私たちを殺しています。興味深いのは、最大の割り当て可能なブロック (VMMap ごとに 1MB) です。これはあまり多くないようです... 正常に動作している別のマシンでは、最大の割り当て可能なブロックは 470MB です...
では、メモリのセグメンテーションをチェックする方法についての指針はありますか?
編集2:
@mikhael によってリンクされた記事 ( http://blog.egilh.com/2006/06/2811aspx.html ) では、32 ビット JVM で許容されるスレッド数の大まかな計算が示されています。
私は仮定するつもりです:
OS プロセス スペースの制限: 2GB 最新の JVM には 250MB が必要です (これは大きな仮定です - リンクされた記事の内容を 2 倍しただけです) スタック サイズ (デフォルトの Oracle): 512KB ヒープ: 512MB PermGen: (正確には思い出せませんが、確かに100MB未満なので、それを使用しましょう)
したがって、最悪のシナリオは次のとおりです。(2GB - .25GB - .5GB - .1GB)/.005GB = 230 スレッド
編集3:
最初に含める必要があった情報: この問題が発生するまで、アプリケーションはしばらくの間 (24 ~ 48 時間など) 正常に動作します。アプリケーションは継続的なバックグラウンド処理を行うため、アイドル時間はほとんどありません。それが重要かどうかはわかりません...
編集4:
詳細情報: 別の障害から VMMap を見ると、ネイティブ ヒープの枯渇が見られます。
ヒープ サイズは 1.2GB で、コミットされるのは 59.8MB だけです。
Java ランタイムに問題があるのでしょうか、それともネイティブ リソースが適切にリリースされていないという問題でしょうか? リリースされていないメモリマップファイルのように?
メモリ マップド ファイルを使用するので、それらに焦点を当てます。
編集4:
次のように発生する例外まで問題を追跡したと思います。
java.lang.OutOfMemoryError
at java.util.zip.Deflater.init(Native Method)
at java.util.zip.Deflater.<init>(Unknown Source)
at java.util.zip.Deflater.<init>(Unknown Source)
at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
at ....
非常に少数のストリーム (現在 4 つの例があります) で空気を抜くと、上記のことが起こります。そして、それが発生すると、VMMap はプロセスのヒープ (JVM ヒープではなく、実際のネイティブ ヒープ) を最大 2GB までスパイクします。それが起こると、すべてがバラバラになります。これは非常に再現性が高くなりました (同じストリームをデフレーターに実行すると、メモリ スパイクが発生します)。
では、JRE の zip ライブラリに問題があるのでしょうか。そんなことになるとはおかしなことですが、本当に途方に暮れています。
まったく同じストリームを別のシステムで実行すると (同じ JRE - 32 ビット、Java 7u45 を実行していても)、問題は発生しません。JRE を完全にアンインストールし、動作を変更することなく再インストールしました。