Вопрос

У нас есть довольно большое и сложное приложение, написанное на 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 и спросить о назначении файловых дескрипторов?

Это было полезно?

Решение

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top