2012-07-05 46 views
2

我在寫一個需要讀/寫大量文件的遺傳算法。 GA的健身測試正在調用名爲gradif的程序,該程序將文件作爲輸入並生成文件作爲輸出。java ioexception error = 24太多文件打開

除了當我將遺傳算法的種羣大小和/或總代數變得太大時,所有東西都在工作。然後,經過這麼多代,我開始得到這個:java.io.FileNotFoundException: testfiles/GradifOut29 (Too many open files)。 (我爲許多不同的文件重複獲取它,索引29只是上次第一次運行它時出現的那個)。這很奇怪,因爲在第一代或第二代之後我沒有收到錯誤信息,但是經過了很長時間後,這意味着每一代都會打開更多的文件,而這些文件不會關閉。但據我所知,我正在關閉所有文件。

代碼設置的方式是main()函數在Population類中,並且Population類包含Individuals的數組。這裏是我的代碼:輸入文件(他們是隨機訪問,這樣我可以重複使用多個代相同的文件)

初始創建

files = new RandomAccessFile[popSize]; 

for(int i=0; i<popSize; i++){ 
    files[i] = new RandomAccessFile("testfiles/GradifIn"+i, "rw"); 
} 

在整個節目的結尾:

for(int i=0; i<individuals.length; i++){ 
    files[i].close(); 
} 

裏面的Individual的體能測試:

FileInputStream fin = new FileInputStream("testfiles/GradifIn"+index); 
FileOutputStream fout = new FileOutputStream("testfiles/GradifOut"+index); 
Process process = Runtime.getRuntime().exec ("./gradif"); 
OutputStream stdin = process.getOutputStream(); 
InputStream stdout = process.getInputStream(); 

然後,後來...

try{ 
     fin.close(); 
    fout.close(); 
    stdin.close(); 
    stdout.close(); 
     process.getErrorStream().close(); 
}catch (IOException ioe){ 
    ioe.printStackTrace(); 
} 

然後,我追加一個'結束'的文件,使它們更容易解析。

FileWriter writer = new FileWriter("testfiles/GradifOut"+index, true); 
writer.write("END"); 
try{ 
    writer.close(); 
}catch(IOException ioe){ 
    ioe.printStackTrace(); 
} 

我對gradif stdin和stdout重定向來自this answer。我嘗試使用try{close()}catch{}語法來查看是否有關閉任何文件(沒有)的問題,並且我從this answer得到了該文件。

還應該注意的是Individual s的健身測試同時運行。

更新:我實際上已經能夠縮小到exec()的電話。在我最近的一次運行中,我第一次遇到了第733代的麻煩(人口規模爲100)。前幾代爲什麼罰款?我不明白爲什麼,如果沒有泄漏,算法應該能夠通過前幾代,但後代失敗。如果有泄漏,那麼它從哪裏來?

UPDATE2:爲了弄清楚這裏發生了什麼,我希望能夠看到(最好是實時的)JVM在任何給定點打開了多少個文件。有沒有簡單的方法來做到這一點?

+0

watch'lsof -p pid' – Thierry

+0

@Thierry我盡我所能,只是在終端上反覆做這件事。但是有沒有什麼辦法可以設置一些能夠實時顯示lsof文件數量的東西,而不必繼續混合'up,enter'鍵? – MattS

+0

是的,這是手錶命令:「watch。定期執行程序,顯示全屏輸出。」。默認間隔爲2秒,但您可以更改它。 – Thierry

回答

0

你似乎在Linux上運行(或某些類Unix操作系統)。你可以使用類似「lsof」命令的東西來確定你的應用程序在出錯時打開了哪些文件。

+0

我看過那個。打開的文件列表看起來應該是它的樣子。再次,這不是一個問題,除了錯誤發生在幾代人之後(比如50代)之外。這對我意味着每一代都打開更多的文件,而不是關閉以前的文件,但似乎並非如此。 – MattS

+0

@MATS - 你是否瀏覽過系統,看看是否某個_other_進程正在使用所有打開的文件? – jtahlborn

+0

有一堆其他文件打開,但這是在服務器上運行。 – MattS

1

也許是把所有你行動的循環中是一個好主意:

while(selection_ of_file.hasNext()){ 
File are new randomFile 
open inputFile 
open outPufile 
read from inputFile 
write to outputFile 
close inputFile 
close outputFile 
} 
1

嘗試關閉錯誤流過:

process.getErrorStream().close(); 

編輯: 其實嘛,你應該閱讀它也是如此,因爲錯誤流上的緩衝區會阻塞子進程。

看一個StreamGobbler實現此處 Need sample Java code to run a shellscript

編輯2: 是否有人口規模(足夠小),用於其無論發生次數的,你沒有遇到的問題?如果是這種情況,你可能不會再泄露已打開的文件/流。

在這種情況下,有兩種解決方法:

  • 要麼重寫你的算法,不把所有的人口文件打開的同時
  • 或增加允許打開的文件的最大數量。請參閱here以瞭解某些方法
+0

原來是這樣 - 我關閉了錯誤流,現在它沒有問題。謝謝! – MattS

+0

沒關係,那不是......它有幫助,但它沒有解決問題。 – MattS

0

如果您確定要關閉所有文件等,可以嘗試使用ulimit。我曾經遇到過一個Java程序碰到ulimit上限的問題。增加它解決了我的問題。我認爲它可能需要服務器重啓,因爲它是內核參數。

+0

但是這並沒有解決如果我能夠超過第一代的問題,那麼我應該能夠讓它超過任何一代人。 – MattS

相關問題