3

プロセスの1つのスレッドダンプを取得しました。これらのスレッドがたくさんあります。彼らはたくさんの記憶を保持していると思うので、私はOOMを取得しています。

"Thread-8264" prio=6 tid=0x4c94ac00 nid=0xf3c runnable [0x4fe7f000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c9bc640> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

"Thread-8241" prio=6 tid=0x4c94a400 nid=0xb8c runnable [0x4faef000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c36b808> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

私はそれがどのようにしてこの状況に到達したのかを調べようとしています。CustomThreadedExtractorWrapperは、スレッドを起動して何らかの作業を行うラッパークラスです(ExtractionThreadは、ZipExtractorCommonsCompressを使用して圧縮ストリームからzipコンテンツを抽出します)。タスクに時間がかかりすぎる場合は、ExtractionThread.interrupt()を呼び出して操作をキャンセルします。

ログを見ると、キャンセルが25回発生したことがわかります。そして、これらのスレッドのうち21個がダンプに表示されます。私の質問:

  1. これらのスレッドのステータスはどうなっていますか?生きていて走っていますか?どういうわけかブロックされましたか?
  2. 彼らはどうやら.interrupt()で死ななかったのですか?本当にスレッドを殺す確実な方法はありますか?
  3. スタックトレースで「ロックされている」とはどういう意味ですか?

Inflater.javaの223行目は次のとおりです。

public synchronized int inflate(byte[] b, int off, int len) {
    ...
    //return is line 223
    return inflateBytes(b, off, len);                          
}
4

4 に答える 4

3

「ロックされている」とは、モニターを所有していることを意味します。つまり、メソッドはsynchronizedであり、スレッドダンプは同期が実行されるインスタンスのアドレスを示します。

でスレッドを強制終了することはできますThread.stop()が、スレッドが抵抗する可能性があり、本質的に安全ではなく、非推奨であり、非常に悪い結果になります。それをしません。その上、ここの場合のように、スレッドがネイティブメソッドにあるときにそれが機能するかどうかはわかりません。

Thread.interrupt()ターゲットスレッドを微調整します。スレッドは、次に割り込みフラグを明示的に確認するか、ブロックする可能性のある操作(I / O、またはwait())を実行するときに、そのことに気付きます。スレッドは例外をキャッチして無視する場合があります。

スレッドは「実行可能」です。ブロックされません。Inflater.inflate()とにかくブロッキング機能ではありません。メモリ内の計算のみを実行します。ネイティブ実装にバグがある可能性があります(ただし、これは非常に安定したコードであるZlibInflater.inflateBytes()に依存しているため、それほど可能性は高くありません)。もっともらしいのは、呼び出し元の1人(クラスなど)が、Zipエクストラクタにさらにゼロバイトを処理するように要求するループでスタックし、再試行する前にさらにデータを待機する必要があることを理解していないことです。ZipExtractorCommonsCompress

于 2010-03-30T12:51:04.823 に答える
2
  1. これらのスレッドはすべて実行可能な状態です

  2. 割り込みはスレッドを強制終了しません...スレッドが中断されているかどうかを示すフラグであり、メソッドはスリープし、待機し、すべてがスレッドの割り込み時にInteruptedExceptionをスローします。中断時にスレッドを停止する場合は、メソッドとisInterupted()を確認し、そのスレッドのすべての作業を終了します。

  3. Lockedは、1つの特定のオブジェクトがそのスレッドによってロックされていることを示します

于 2010-03-30T12:46:26.830 に答える
0

可能であれば、jvisualvm(JDKインストールのbinフォルダーにあります)を使用することをお勧めします。ローカルのJavaプロセスに接続して、スレッド情報とメモリ情報(使用状況、割り当てられたオブジェクトなど)を提供できます。インターフェイスは、コンソールダンプよりもはるかに簡単に解釈できます。あなたの質問のために:

Thread.Stateの定義はAPIにあります。

NEW - A thread that has not yet started is in this state.
RUNNABLE - A thread executing in the Java virtual machine is in this state.
BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
TERMINATED - A thread that has exited is in this state.

したがって、上記のトレースの2つのスレッドは生きています(実行可能とは、実行可能であることを意味しますが、必ずしも実行中である必要はありません。つまり、OSスケジューラーは、別のスレッドの実行中にスレッドを一時停止する場合があります)。

スレッドを「殺す」ための可能な方法:

  • キャッチされていない例外があります
  • スレッドのstop()を呼び出す
  • スレッドを正常に実行します(つまり、run()を終了します)。

3番目の質問についてはわかりませんが、これはスレッドが保持している内部ロックへの参照であると思います。

于 2010-03-30T12:48:02.340 に答える
0

本当にスレッドを殺す確実な方法はありますか?

いいえ、ありません。

あなたが観察Thread.interrupt()したように、スレッドに停止するようにアドバイスしますが、気付かないか、注意を払わないと判断する場合があります。

他の唯一の選択肢はThread.stop()です。これは、アプリケーションを深刻に不安定にする可能性があるため、非推奨になりました。具体的にThread.stop()は、すべてのスレッドロックを解放しますが、ロックによって保護されている状態が表示されるようになっていることを保証するものではありません。同時に、予期しない例外は、によって中断されたメソッドが、stop()(たとえば)notify()待機している他のスレッドにアクセスする機会を得られないことを意味します。最後に、スレッドがThreadDeath例外オブジェクトをキャッチする(そして再スローしない)ことが可能であり、スレッドstop()をまったく停止させません。

要するに、電話Thread.stop()は本当に、本当に悪い考えです。

于 2010-03-30T13:10:47.850 に答える