Освобождение дескрипторов Java-файлов
У нас есть довольно большое и сложное приложение, написанное на Java, которое выполняется поверх пакета Gridgain. Проблема, с которой я сталкиваюсь, заключается в том, что это приложение будет сидеть там, обрабатывая запросы в течение приблизительно одного дня, прежде чем каждый запрос начнется, что приведет к исключению типа java.nio.channels.ClosedByInterruptException.
Я предполагаю, что приложение не выпускает файловые дескрипторы, и после дня непрерывного использования оно заканчивается и больше не может продолжать обрабатывать запросы (каждый запрос требует чтения нескольких файлов из каждого узла сетки). Мы завернули большинство наших файловых операций ввода-вывода в такие классы, как этот
package com.vlc.edge;
import com.vlc.common.VlcRuntimeException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public final class BufferedReaderImpl implements BufferedReader {
private java.io.BufferedReader reader;
public BufferedReaderImpl(final String source) {
this(new File(source));
}
public BufferedReaderImpl(final File source) {
try {
reader = new java.io.BufferedReader(new FileReader(source));
} catch (FileNotFoundException e) {
throw new VlcRuntimeException(e);
}
}
public BufferedReaderImpl(final Reader reader) {
this.reader = new java.io.BufferedReader(reader);
}
public String readLine() {
try {
return reader.readLine();
} catch (IOException e) {
throw new VlcRuntimeException(e);
}
}
public void close() {
try {
reader.close();
} catch (IOException e) {
throw new VlcRuntimeException(e);
}
}
}
Я думаю, что проблема в том, что этот дизайн явно не освобождает дескриптор файла, мое предлагаемое решение состоит в том, чтобы добавить метод finalize, подобный этому
protected void finalize() throws Throwable
{
reader.close();
super.finalize();
}
который сделает это явно. Вопрос (наконец) заключается в том, может ли это оказать какое-либо влияние. У классов, таких как java.io.BufferedReader, уже есть какой-то механизм для решения этого типа проблемы?
РЕДАКТИРОВАТЬ: Также высоко ценится здесь способы проверки, действительно ли это проблема... то есть есть ли способ запросить работающую JVM и спросить о его распределении дескриптора файла?
3 ответа
Нет смысла переопределять finalize()
, Если дескриптор получает сборщик мусора и завершает его работу, то это относится и к экземпляру java.io.BufferedReader
и это будет закрыто.
Возможно (согласно спецификации), что дескриптор собирается мусором, но не завершается, но это не очень вероятно.
Вы можете попробовать использовать PhantomReference
s для очистки неиспользуемых файловых дескрипторов, но я предполагаю, что ваши экземпляры BufferedReaderImpl
все еще ссылаются откуда-то (например, значения в Map
от имен файлов до открытых дескрипторов), и именно это мешает им закрыться (в этом случае финализаторы не помогут.)
Финализаторы нельзя полагаться на вызов. Это не очень хороший подход к управлению ресурсами. Стандартная конструкция в Java для этого:
InputStream in = null;
try {
in = ...;
// do stuff
} catch (IOException e) {
// error
} finally {
if (in != null) { try { in.close(); } catch (Exception e) { } }
in = null;
}
Вы можете захотеть обернуть эти маркеры внутри класса, но это не надежный подход.
Спецификация Java говорит, что это не гарантирует, чтоfinalize()
будет выполнен. Ваш код должен явно закрыться FileReader
сам.