Освобождение дескрипторов файла Java - PullRequest
1 голос
/ 22 октября 2009

У нас есть довольно большое и сложное приложение, написанное на 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 ]

12 голосов
/ 22 октября 2009

Финализаторы не могут полагаться на вызов. Это не очень хороший подход к управлению ресурсами. Стандартная конструкция в Java для этого:

InputStream in = null;
try {
  in = ...;
  // do stuff
} catch (IOException e) {
  // error
} finally {
  if (in != null) { try { in.close(); } catch (Exception e) { } }
  in = null;
}

Возможно, вы захотите обернуть эти маркеры внутри класса, но это не надежный подход.

5 голосов
/ 22 октября 2009

Нет смысла переопределять finalize(). Если дескриптор получает сборщик мусора и завершает его работу, то экземпляр java.io.BufferedReader также закрывается.

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

Вы можете попробовать использовать PhantomReference s для очистки неиспользуемых файловых дескрипторов, но я предполагаю, что ваши экземпляры BufferedReaderImpl все еще ссылаются откуда-то (например, значения в Map из имен файлов для открытия дескрипторов) и что это то, что мешает им закрыться (в этом случае финализаторы не помогут.)

1 голос
/ 22 октября 2009

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

...