15

広く展開されているアプリケーションがあります (数百のワークステーションで実行されています)。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つの可能性が残ります。

  1. 一時的な状態により、膨大な数のスレッドが作成されています (ただし、これらのスレッドは、診断を行う前に破棄されます)。
  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 を完全にアンインストールし、動作を変更することなく再インストールしました。

4

2 に答える 2

4

最後にこれを理解しました。

私たちが処理したいくつかのデータ ストリーム (このサイトでは 1,000 万のうち 4 つ) があり、大量の DeflaterOutputStream オブジェクトが作成されました。私たちが使用していたサードパーティのライブラリは、ストリームで close() の代わりに finish() を呼び出していました。基礎となる Deflater ファイナライザーは物事をクリーンアップしていたので、負荷が高すぎない限り、問題はありませんでした。しかし、転換点を過ぎると、次のような問題に直面するようになりました。

http://jira.pentaho.com/browse/PRD-3211

これが私たちを導きました:

http://bugs.sun.com/view_bug.do?bug_id=4797189

それが起こってから数時間後、システムはついに脱出できない窮地に陥り、必要なときにネイティブスレッドを作成できなくなりました.

修正は、サード パーティのライブラリを入手して DeflaterOutputStream を閉じることでした。

したがって、間違いなくネイティブ リソース リークです。他の誰かがこのような問題に遭遇したことがある場合、VMMap ツールは、問題の原因となっているデータ ストリームを最終的に追跡するために不可欠でした。

于 2013-11-18T23:43:50.713 に答える
0

証明するのは明らかに困難ですが、32 ビットのメモリ割り当ての問題が発生していると思われます。

スレッドは、実行するために連続している必要があるヒープ メモリではなく、ネイティブ メモリに割り当てられます。WOW64 では 32 ビット プロセスが 4 GB を超える領域で動作できると確信していますが、4 GB の制限を超える新しいスレッドにネイティブ メモリを割り当てることについてはよくわかりません。

したがって、アプリケーションとヒープは低めのメモリにあり、他のプロセスは介在する 3.07 ギガ (メモリが機能する場合) を使用し、新しいスレッドを作成するために、最初の呼び出し元より 4 GB 上のネイティブ メモリ ブロックを割り当てようとします。

この問題は、メモリ使用量が 4 GB 前後またはそれ以上の場合にのみ発生することを確認していただけますか?

于 2013-11-15T17:40:37.160 に答える