2

Gridgain パッケージ上で実行されている Java で書かれたかなり大規模で複雑なアプリケーションがあります。私が抱えている問題は、すべてのリクエストが開始される前に、このアプリケーションが約 1 日間リクエストを処理し続け、タイプ java.nio.channels.ClosedByInterruptException の例外が発生することです。

私の推測では、アプリケーションがファイル ハンドルを解放しておらず、1 日連続して使用した後、ファイル ハンドルがなくなり、リクエストの処理を続行できなくなります (各リクエストには、各グリッド ノードから複数のファイルを読み取る必要があります)。ファイル IO 操作のほとんどを、このようなクラスでラップしました。

package com.vlc.edge;

import com.vlc.common.VlcRuntimeException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public final class BufferedReaderImpl implements BufferedReader {
    private java.io.BufferedReader reader;

    public BufferedReaderImpl(final String source) {
        this(new File(source));
    }

    public BufferedReaderImpl(final File source) {
        try {
            reader = new java.io.BufferedReader(new FileReader(source));
        } catch (FileNotFoundException e) {
            throw new VlcRuntimeException(e);
        }
    }

    public BufferedReaderImpl(final Reader reader) {
        this.reader = new java.io.BufferedReader(reader);
    }

    public String readLine() {
        try {
            return reader.readLine();
        } catch (IOException e) {
            throw new VlcRuntimeException(e);
        }
    }

    public void close() {
        try {
            reader.close();
        } catch (IOException e) {
            throw new VlcRuntimeException(e);
        }
    }
}

問題は、この設計がファイル ハンドルを明示的に解放しないことだと思います。私の提案する解決策は、このようなファイナライズ メソッドを追加することです。

    protected void finalize() throws Throwable
    {
        reader.close();
        super.finalize();   
    }

これは明示的にこれを行います。(最終的に)問題は、これが何らかの影響を与える可能性があるかどうかです。java.io.BufferedReader などのクラスには、この種の問題に対処するメカニズムが既に備わっているのでしょうか?

編集:また、これが実際に問題であるかどうかを確認する方法も非常に高く評価されています...つまり、実行中のJVMにクエリを実行し、そのファイルハンドルの割り当てについて尋ねる方法はありますか?

4

3 に答える 3

13

ファイナライザーが呼び出されることに依存することはできません。これは、リソース管理には適した方法ではありません。このための Java の標準構造は次のとおりです。

InputStream in = null;
try {
  in = ...;
  // do stuff
} catch (IOException e) {
  // error
} finally {
  if (in != null) { try { in.close(); } catch (Exception e) { } }
  in = null;
}

これらのハンドルをクラス内にラップすることもできますが、それは堅牢な方法ではありません。

于 2009-10-22T04:02:38.913 に答える
6

オーバーライドする意味はほとんどありませんfinalize()。ハンドルがガベージ コレクションされてファイナライズされている場合、のインスタンスも同様でjava.io.BufferedReaderあり、閉じられます。

(仕様によると) ハンドルがガベージ コレクションされているがファイナライズされていない可能性がありますが、これはほとんどありません。

s を使用して未使用のファイル ハンドルをクリーンアップすることもできPhantomReferenceますが、私の推測では、 のインスタンスBufferedReaderImplはまだどこかから参照されており (たとえばMap、ファイル名からハンドルを開くまでの a の値)、それがそれらを閉じられない原因となっています (この場合、ファイナライザーは役に立ちません。)

于 2009-10-22T04:18:24.653 に答える
1

finalize()Java の仕様では、' ' が実行されることは保証されていません。コードは明示的にFileReader自分自身を閉じる必要があります。

于 2009-10-22T04:04:54.193 に答える