Javaファイルハンドルの解放
質問
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を照会し、ファイルハンドルの割り当てについて尋ねる方法はありますか?
解決
finalize()
をオーバーライドしてもほとんど意味がありません。ハンドルがガベージコレクションされてファイナライズされる場合、 java.io.BufferedReader
のインスタンスもそうであり、閉じられます。
(仕様によれば)ハンドルがガベージコレクションされているが、ファイナライズされていない可能性がありますが、これはほとんどありません。
PhantomReference
を使用して未使用のファイルハンドルをクリーンアップすることもできますが、 BufferedReaderImpl
のインスタンスはまだどこからでも参照されている(たとえば、< code> Map をファイル名から開いているハンドルへ)、それがそれらを閉じることを妨げているものです(この場合、ファイナライザは役に立ちません。)
他のヒント
ファイナライザーを呼び出すことはできません。リソース管理のための良いアプローチではありません。このためのJavaの標準構造は次のとおりです。
InputStream in = null;
try {
in = ...;
// do stuff
} catch (IOException e) {
// error
} finally {
if (in != null) { try { in.close(); } catch (Exception e) { } }
in = null;
}
これらのハンドルをクラス内にラップすることもできますが、それは堅牢なアプローチではありません。
Java仕様では、「 finalize()
」が実行されることを保証するものではないとされています。コードは、 FileReader
を自分で明示的に閉じる必要があります。