Освобождение дескрипторов 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 и это будет закрыто.

Возможно (согласно спецификации), что дескриптор собирается мусором, но не завершается, но это не очень вероятно.

Вы можете попробовать использовать PhantomReferences для очистки неиспользуемых файловых дескрипторов, но я предполагаю, что ваши экземпляры 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 сам.

Другие вопросы по тегам