1

私が何かをするなら私は知っています

copyFromInToOut(new FileInputStream(f1), new FileOutputStream(f2));
System.gc();

それらに対してGCを実行し、それらFileInputStreamを閉じます。しかし、私がそうするなら

copyFromInToOut(new BufferedInputStream(new FileInputStream(f1)), new BufferedOutputStream(new FileOutputStream(f2));
System.gc();

FileOutputStreamがBufferedOutputStreamの前にGCされ、バッファーがフラッシュされないという危険性はありますか?これよりも多くの手順が必要なため、flush、closeを呼び出すことはできません。最初に、bufferedinputstreamを宣言し、渡してから、closeを呼び出します。または私はこれを安全に行うことができますか?

4

4 に答える 4

8

System.gc()明示的に呼び出さないでください。ファイナライザーに頼って何かをしないでください。特に、ガベージコレクションがどのように機能するかを理解していない場合。明示的なガベージコレクション要求は無視でき、ファイナライザーは実行されない可能性があります。

ストリーム用に適切に記述されたcopyFromInToOutメソッドは、内部で独自のバッファーを使用する可能性が高いため、出力をラップする必要はありません。

FileInputStreamとの変数を宣言し、ブロック内のそれぞれでFileOutputStream呼び出します。close()finally

FileInputStream is = new FileInputStream(f1);
try {
  FileOutputStream os = new FileOutputStream(f2);
  try {
    copyFromInToOut(is, os);
    os.flush();
  } finally {
    os.close();
  }
} finally {
  is.close();
}
于 2010-10-13T22:09:34.057 に答える
5

close()GCdの場合、私が知っているInputStreamの実装はありません。close()InputStreamを手動で行う必要があります。

編集:どうやらFileInputStreamは私が気付いていなかったfinalizeメソッドであなたのためにclose()をしますが、これに頼るべきではない理由のために他の答えを見てください。

上記の両方の例では、入力ストリームと出力ストリームの両方を閉じる必要があります。ラップされたバッファの場合、およびラップされたケースの場合、この場合はclose()最も外側のを呼び出すだけで済みます。InputStreamBufferedInputStream

于 2010-10-13T21:58:27.223 に答える
2

そうするときに実際に何が起こっているのかを分析するのは興味深いことですが、そうしないでください。

常にストリームを明示的に閉じてください。

(あなたの質問に答えるために、はい、gcが発生し、それらが失われたときに、バッファー内のバイトがファイルi / oストリームにフラッシュされていない可能性があります)

于 2010-10-13T22:06:01.500 に答える
2

@ericksonの回答に示されているパターンを使用して、ストリームを明示的に閉じる必要があります。ストリームを閉じるためにファイナライズに依存することは、本当に悪い考えです:

  1. System.gc()特に(何かを行う場合)toが完全なガベージコレクションをトリガーする可能性があるため、呼び出しにはコストがかかります。これにより、ヒープ内の到達可能なすべてのオブジェクトのすべての参照がトレースされます。

  2. javadocsを読むとSystem.gc()、GCを実行するためのJVMへの「ヒント」にすぎないことがわかります。JVMは、ヒントを無視してかまいません...次の問題に進みます。

  3. GCを明示的に実行しないと、GCが実行されるまでに長い時間がかかる場合があります。それでも、ファイナライザーがすぐに実行される保証はありません。

その間:

  • 開いているすべてのファイルは開いたままになり、他のアプリケーションがそれらを使用できなくなる可能性があります
  • ストリーム内の未書き込みのデータは未書き込みのままです
  • Javaアプリケーションで、他のストリームを開くときにファイル記述子スロットが不足するという問題が発生することもあります。

そして、出力ストリームを処理するためにファイナライズに依存することには、最後の問題が1つあります。ファイナライズ時にストリームにフラッシュされていないデータがある場合、出力ストリームクラスはそのデータをフラッシュしようとします。ただし、これはすべて、アプリケーションのスレッドの1つではなく、JVM内部スレッドで発生します。したがって、フラッシュが失敗した場合(たとえば、ファイルシステムがいっぱいであるため)、アプリケーションは結果の例外をキャッチできず、したがって、それを報告することも、回復するために何かをすることもできません。

編集

Object.finalize()元の質問に戻ると、BufferedOutputStreamクラスはデフォルトのメソッドをオーバーライドしないことがわかりました。つまり、BufferedOutputStreanは、ガベージコレクション時にまったくフラッシュされません。バッファ内の書き込まれていないデータはすべて失われます。

これが、ストリームを明示的に閉じるもう1つの理由です。実際、この特定のケースでは、呼び出しSystem.gc()は単なる悪い習慣ではありません。また、データの損失につながる可能性があります。

于 2010-10-13T22:34:02.190 に答える