web-dev-qa-db-ja.com

入力ストリームをclose()するのが良いのはなぜですか?

私はJavaプログラミング言語で音の経験があります。しかし、私の心の中で常に心に留めていることの1つは、なぜclose() _Java.io.InputStream_またはそのサブクラス?

ここで_Java.io.OutputStream_を使用して、FileOutputStreamと言います。ファイルに書き込んだ後、出力ストリームをclose()しない場合、ファイルに書き込むつもりのデータはバッファであり、ファイルには書き込まれません。

そのため、close()OutputStreamが必要になります。しかし、私は後に苦い経験を​​したことはありません 閉じない InputStream

しかし、インターネットと本のすべての記事は、ストリームを閉じることは常に良いことであり、InputStreamまたはOutputStreamであると言っています。

だから私の質問は、なぜclose()InputStreamが必要になるのかということです。人々はあなたがあなたのメモリリークに直面するかもしれないと言っていますclose()しないでください。それでは、どのようなメモリリークですか?

34
Aditya Singh

InputStreamは、小さなカーネルリソース、低レベルのファイルハンドルを拘束します。さらに、ファイルを読み取り用に開いている限り、ファイルはある程度(削除、名前変更から)ロックされます。ロックされたファイルを気にしていなかったとしましょう。最終的に、別のファイルを読み込んで新しいInputStreamで開く必要がある場合、カーネルは新しい記述子(ファイルストリーム)を順番に割り当てます。これは追加されます。

実行時間の長いアプリケーションでプログラムが失敗するまでの時間の問題です。

プロセッサのファイル記述子テーブルのサイズは限られています。最終的に、ファイルハンドルテーブルはプロセスの空きスロットを使い果たします。何千もの場合でも、長時間実行されているアプリケーションではこれを簡単に使い果たす可能性があります。その時点で、プログラムは新しいファイルまたはソケットを開くことができなくなります。

プロセスファイル記述子テーブルは、次のように単純化されています。

IOHANDLE fds[2048];  // varies based on runtime, IO library, etc.

あなたは3つのスロットを占有することから始めます。それを満たせば、あなた自身にサービス拒否攻撃を実行したことになります。

知っておくと便利です。それをどのように適用するのが最善ですか?

ローカルオブジェクトに依存してスコープ外に出る場合は、ガベージコレクターに任せてください。ガーベッジコレクターは、独自のスイートタイムでそれを取得できます(非決定的)。そのため、GCに依存せず、明示的に閉じてください。

Javaでは、Java.lang.AutoCloseableを実装する型でtry-with-resourcesを使用する必要があります。これには、ドキュメントごとに「Java.io.Closeableを実装するすべてのオブジェクトが含まれます」: https://docs.Oracle .com/javase/tutorial/essential/exceptions/tryResourceClose.html

C#では、同等のものはIDisposableを実装するオブジェクトの「using」ブロックです

41
codenheim

memoryリークではなく、ファイルハンドルリークです。オペレーティングシステムは、単一のプロセスが特定の数のファイルを開くことのみを許可します。入力ストリームを閉じない場合、JVMがそれ以上開くことを禁止する可能性があります。

8

これは潜在的なリソースリークです。このように質問すると、継承によって、どのリソースがリークされる可能性があるかを正確に知ることができなくなります。たとえば、閉じる必要のあるリソースを割り当てないVoidInputStreamという独自のクラスを作成できます。しかし、それを閉じないと、継承された契約に違反していることになります。

さまざまな入力ストリームのリストについては、 http://docs.Oracle.com/javase/7/docs/api/Java/io/InputStream.html を参照してください。

リークされたリソースのテストは非常に困難です。次に、同時実行性の問題をテストします。あなたが無意識のうちに小さな混乱を引き起こしていないことを確認しないでください。

5
candied_orange

開いているファイルやソケットなど、InputStreamに関連付けられているOSリソースはいくつあってもかまいません。 close()はこれらのリソースを解放します。

プログラムは、どの種類のInputStreamを使用しているかを知る必要はありません。使用後にストリームが閉じられ、リソースが解放されるという規約に従う必要があります。

2
Thomas Stets