2012-07-05 3 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 «s:

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 взяты из this answer. Я попытался использовать синтаксис try{close()}catch{}, чтобы увидеть, есть ли проблема с закрытием любого из файлов (там не было), и я получил это от this answer.

Следует также отметить, что тесты пригодности Individual s проходят одновременно.

UPDATE: Я действительно смог сузить его до звонка exec(). В моем последнем запуске я впервые столкнулся с проблемой в поколении 733 (с размером населения 100). Почему более ранние поколения прекрасны? Я не понимаю, почему, если нет утечки, алгоритм должен иметь возможность передавать более ранние поколения, но терпеть неудачу на последующих поколениях. И если есть утечка, то откуда это?

UPDATE2: Чтобы выяснить, что здесь происходит, я хотел бы видеть (желательно в режиме реального времени), сколько файлов открылось JVM в любой заданной точке. Есть ли простой способ сделать это?

+0

watch 'lsof -p pid' – Thierry

+0

@Thierry Я сделал это как можно лучше, просто повторю это в терминале. Но можно ли каким-то образом создать то, что покажет количество файлов lsof в режиме реального времени, без меня нужно будет замять клавиши «вверх, входить»? – MattS

+0

Да, это команда watch: «watch. Выполняйте программу периодически, показывая полный выход». интервал по умолчанию составляет 2 секунды, но вы можете его изменить. – Thierry

ответ

0

Вы, кажется, работаете на linux (или какой-то операционной системе, подобной UNIX). вы можете использовать что-то вроде команды «lsof», чтобы выяснить, какие файлы открывают ваше приложение, когда вы получаете ошибку.

+0

Я посмотрел на это. Список открытых файлов кажется таким, каким он должен выглядеть. Опять же, это не будет проблемой, за исключением того, что ошибка возникает после нескольких поколений (например, 50 поколений). Это означало бы, что каждое поколение открывает больше файлов и не закрывает предыдущие, но это, похоже, не так. – MattS

+0

@MattS - просмотрели ли вы систему, если какой-то процесс _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(); 

EDIT: Ну на самом деле вы должны прочитать он также, поскольку буфер, заполненный потоком ошибок, блокирует дочерний процесс.

взгляд на реализацию StreamGobbler здесь: Need sample Java code to run a shellscript

EDIT 2: Есть ли численность населения (достаточно мал), для которых независимо от количества поколения, вы не столкнетесь вопрос? Если это так, вы можете не пропускать больше открытых файлов/потоков.

В этом случае у вас есть два решения:

  • Либо переписать алгоритм не держать все файлы населения открыты одновременно
  • или увеличить максимальное количество разрешенных открытых файлов. См. here для некоторого способа сделать это
+0

Оказывается, это было - я закрыл поток ошибок, и теперь это не проблема. Благодаря! – MattS

+0

Ничего, это было не так .... Это помогло, но это не решило проблему. – MattS

0

Если вы уверены, что закрываете все файлы и т. Д., Возможно, попробуйте улучшить ulimit. У меня был вопрос, когда программа java продолжала натыкаться на потолок. Увеличивая его, я решил проблему. Я думаю, что это может потребовать перезагрузки сервера, поскольку это параметр ядра.

+0

Но это не касается вопроса о том, что, если я смогу прогнать его даже из первого поколения, я должен уметь пройти мимо любого количества поколений. – MattS

Смежные вопросы