1

そのため、gridgain の上で実行されているアプリケーションがあり、約 12 ~ 24 時間のストレス テストで問題なく動作し始めました。この期間が過ぎると、アプリケーションは突然、例外 java.nio.channels.ClosedByInterruptException ですべてのクエリに応答し始めます (完全なスタック トレースはhttp://pastie.org/664717にあります)。

失敗している方法は(@stephencフィードバックを使用するように編集されています

public static com.vlc.edge.FileChannel createChannel(final File file) {
    FileChannel channel = null;
    try {
    channel = new FileInputStream(file).getChannel();
    channel.position(0);
    final com.vlc.edge.FileChannel fileChannel = new FileChannelImpl(channel);
    channel = null;
    return fileChannel;
    } catch (FileNotFoundException e) {
    throw new VlcRuntimeException("Failed to open file: " + file, e);
    } catch (IOException e) {
    throw new VlcRuntimeException(e);
    } finally {
    if (channel != null) {
        try {
        channel.close();
        } catch (IOException e){
        // noop
        LOGGER.error("There was a problem closing the file: " + file);
        }
    }
    }
}

呼び出し元の関数がオブジェクトを正しく閉じる

private void fillContactBuffer(final File signFile) {
    contactBuffer = ByteBuffer.allocate((int) signFile.length());
    final FileChannel channel = FileUtils.createChannel(signFile);
    try {
        channel.read(contactBuffer);
    } finally {
        channel.close();
    }
    contactBuffer.rewind();
}

アプリケーションは基本的に分散ファイル パーサーとして機能するため、これらのタイプの操作を多数実行します (通常、ノードごとのクエリごとに約 10 のチャネルを開きます)。一定期間が経過すると、ファイルを開くことができなくなったようです。なぜこれが起こっているのかを説明するのに途方に暮れています.それを下げて修正します。ファイルハンドルの枯渇に関連している可能性がある場合は、確実に見つけるためのヒントを聞きたいです...つまり、実行中にJVMを照会するか、Linuxコマンドラインツールを使用して、現在開いているハンドルに関する詳細情報を見つけます.

更新:コマンド ライン ツールを使用して lsof の出力を調査しましたが、ファイル ハンドルが開いたままになっているという証拠は確認できませんでした... グリッド内の各ノードには、開いたファイルの非常に安定したプロファイルがあります。上記のコードが実行されると変化が見られます...しかし、常に安定した数の開いているファイルに戻ります。

この質問に関連: Java ファイル ハンドルの解放

4

1 に答える 1

2

ファイル ハンドルが閉じられないシナリオがいくつかあります。

  1. ファイルを開くコードが他にもある可能性があります。
  2. createChannel(...)呼び出すコードと呼び出さないコードが他にもあるかもしれませんfillContactBuffer(...)
  3. 例外がスローされた場合channel.position(0)、チャネルは閉じられません。try修正は、次のステートメントがブロック内にあるようにコードを再配置することです。

    channel.position(0);
    return new FileChannelImpl(channel);
    

編集: スタック トレースを見ると、2 つのメソッドが異なるコードベースにあるようです。私はそのcreateChannel方法に責任があると思います。問題の原因ではない場合でも、漏れている可能性があります。例外が発生した場合にチャネルが閉じていることを確認するには、in internalfinally句が必要です。

このようなものがうまくいくはずです。finally成功時にブロックがチャネルを閉じないようにする必要があることに注意してください!

public static com.vlc.edge.FileChannel createChannel(final File file) {
    final FileChannel channel = null;
    try {
        channel = new FileInputStream(file).getChannel();
        channel.position(0);
        FileChannel res = new FileChannelImpl(channel);
        channel = null;
        return res;
    } catch (FileNotFoundException e) {
        throw new VlcRuntimeException("Failed to open file: " + file, e);
    } catch (IOException e) {
        throw new VlcRuntimeException(e);
    } finally {
        if (channel != null) {
            try {
                channel.close();
            } catch (...) {
                ... 
            }
        }
    }
}

ずっと後のフォローアップ

考えられる原因としてファイル ハンドル リークが排除されたことを考えると、次の理論は、サーバー側が実際にはThread.interrupt(). 一部の低レベル I/O 呼び出しは、例外をスローすることによって割り込みに応答します。ここでスローされるルート例外は、そのような例外の 1 つに見えます。

これは、なぜこれが起こっているのかを説明するものではありませんが、過負荷またはデッドロックの問題を解決しようとしているのは、サーバー側のフレームワークだったと思います。

于 2009-10-22T07:31:27.603 に答える