2010-11-27 7 views
34

私は複数のファイルに書き込もうとしていますが、正確には19です。それらに何百回も書いた後、私はJava IOExceptionを取得します:開いているファイルが多すぎます。しかし、私が言ったように、私はちょうど19のファイルを開いていると私はすべての冒頭にそれらを開いた。ここでの問題は何ですか?書き込みが成功したことを確認できます。Javaオープンファイルが多すぎます

編集: 私はtry-catch-finallyブロックを使用していませんでした。私は代わりに関数を例外をスローしました。今私はtry-catch-finallyをそれらの周りに置くので、彼らはよりよくやっているようです。

あなたのほとんどは、私が思っていたよりも多くのファイルを開いているという点で大丈夫でした。まだ物事を追跡しています。私は少し後に更新を掲載します。

再編集: すべてのファイルアクセスがtry-catchでラップされていることを確認し、最終的に問題を修正しました。ありがとう

+2

ファイルを開く関数にコメントを入れ、それぞれを1回だけ開いていることを確認します。 –

+0

これらの19のいずれかのためにこのエラーが発生することをどのように知っていますか? Java自体または使用しているフレームワークがファイルを開く可能性があります。 – robert

+3

あなたのコードを投稿してください。おそらくあなたはループ内でそれらを開いているので、何度も繰り返されます。 – harschware

答えて

43

Linuxおよび他のUNIX/UNIXライクなプラットフォームでは、OSはプロセスがいつでも持つことができるオープンファイル記述子の数に制限を設けます。昔は、この制限は固定配線されていましたが、と比較的小さくなりました。今日ではそれははるかに大きく(数百/数千)、プロセスごとに構成可能なリソースの制限が「ソフト」になる可能性があります。 (ulimitシェルを参照してください...)

Javaアプリケーションがプロセスごとのファイル記述子の制限を超えている必要があります。

あなたは19個のファイルが開いていると言いますが、数百回後に "too many files open"というIOExceptionが発生します。この特定の例外は、新しいファイル記述子が要求されたときにのみ発生します。すなわち、の場合は、ファイル(またはパイプまたはソケット)を開きます。 を確認するには、IOExceptionのstacktraceを出力します。

リソース制限が小さい(これはほとんどそうではない)アプリケーションを実行している場合を除き、ファイル/ソケット/パイプを繰り返し開いて閉じていなければなりません。それがなぜ起こっているのかを調べ、それについて何をすべきかを理解できるはずです。

FYIの次のパターンは、ファイル記述子をリークしないことが保証されているファイルに書き込む安全な方法です。

Writer w = new FileWriter(...); 
try { 
    // write stuff to the file 
} finally { 
    try { 
     w.close(); 
    } catch (IOException ex) { 
     // Log error writing file and bail out. 
    } 
} 

1 - カーネルにコンパイルのようにハードワイヤード。利用可能なfdスロットの数を変更すると、再コンパイルが必要となり、他のものに利用できるメモリが少なくなる可能性があります。 Unixが16ビットマシン上で動作する時代には、これらのことは本当に重要でした。

UPDATE

のJava 7の方法は、より簡潔である:

try (Writer w = new FileWriter(...)) { 
    // write stuff to the file 
} // the `w` resource is automatically closed 

UPDATE 2

どうやらあなたはまた、 "あまりにも多くのファイルのオープンを" 遭遇することができます外部プログラムを実行しようとしています。基本的な原因は上記のとおりです。ただし、exec(...)でこれが発生する理由は、JVMが外部アプリケーションの標準入力/出力/エラーに接続される "パイプ"ファイル記述子を作成しようとしているためです。

+7

私は[IOUtils.closeQuietly()](http://commons.apache.org/io/apidocs/org/apache/commons/io/IOUtils.html#closeQuietly(java。 io.Writer)) – yegor256

+12

私もそれを使用します。しかし、私はあなたが2分であなた自身を書くことができる方法を得るために、その依存性を追加することをお勧めしません。 –

+1

実際、2016年にはリソース*で試してみることを強くお勧めします。つまり「Java 7ウェイ」となります。 Java 6以前を使用している場合は、アップグレードする必要があります。 Java 6は現在4年間メンテナンスされていません。 –

1

あなたは明らかに新しいものを開く前にあなたのファイル記述子を閉じることはありません。あなたは窓かLinuxか?

+0

彼が実際に19のファイルを開き、ファイル記述子を持つ配列を持っていれば、彼はうまくいくはずですが、彼は実際に彼が思っている以上に開いていると思います。 –

+0

AFAIK、Windowsにはこの問題はありません。例えば、私のXP SP3では、開かれたファイルを閉じずにCXF(約15K)ファイルのソースツリー全体を辿ることができました。 –

+0

私はウィンドウにファイル記述子の制限があることを保証します。それはちょうど65000にデフォルトするかもしれません – Falmarri

-7

最近、私はプログラムバッチ処理ファイルを持っていましたが、私は確かにループ内の各ファイルを閉じましたが、エラーはまだそこにあります。スティーブンCが示唆したように高い値に最大ファイルディスクリプタ値を変更し、

:UNIXの場合

int index; 
while() { 
    try { 
     // do with outputStream... 
    } finally { 
     out.close(); 
    } 
    if (index++ % 100 = 0) 
     System.gc(); 
} 
+7

申し訳ありませんが、誤解されています。 *すべてのストリームを明示的に閉じたと思うかもしれませんが、プログラムのどこかにストリームが閉じられないという実行パスがあります。 GCを実行すると、「失われた」ストリームがファイナライズされます。ストリームファイナライズは 'this.close()'(IIRC)を呼び出します。 –

+0

gc()はストリームを閉じますが、知っておくとよいでしょう。 –

+0

@StefanReichそうではありません。ファイル記述子を閉じます。ストリームはフラッシュされないままです。 – EJP

1

以降、私はゴミで、この問題を解決するには、熱心にファイルのすべての何百もの収集しますこの問題を回避します。

は、あなたの現在のファイルディスクリプタの能力を見て試してみてください。 ulimit -n

変化よりもあなたの必要性に応じて!

これが役に立ちます。ありがとう!

1

ほとんどの一般的なケースでは、ファイルハンドルが閉じられていないというエラーは非常にはっきりしていますが、Linux上のJDK7でインスタンスが発生したばかりです...ここで十分説明しています。

プログラムは、FileOutputStream(fos)、BufferedOutputStream(bos)、およびDataOutputStream(dos)を開きました。データ出力ストリームに書き込んだ後、DOSは閉じられ、すべてがうまくいったと思った。

しかし、dosは、ディスクフルエラーを返したボスをフラッシュしようとしました。その例外はDataOutputStreamによって奪取され、その結果、基底のボスは閉じられなかったため、fosはまだ開いていました。

その後、ファイル名が(.tmpのものから)本名に変更されました。それによって、Javaファイル記述子トラッカーは元の.tmpのトラックを失っていましたが、まだ開いていました!

これを解決するには、まず自分自身でDataOutputStreamをフラッシュし、IOExceptionを取得してFileOutputStreamを閉じなければなりませんでした。

私はこれが誰かを助けてくれることを願っています。

+0

これは意味をなさない。 'DataOutputStream'は例外を受け入れません。 'FilterOutputStream.close()'は行いますが、閉じるのを抑制する方法ではありません。 「Javaファイル記述子トラッカー」については、元の.tmpの「los [ing] track」には、意味が分かりません。 – EJP