Pregunta

Tenemos una aplicación bastante grande y compleja escrita en Java que se ejecuta sobre el paquete Gridgain. El problema que tengo es que esta aplicación se quedará allí procesando las solicitudes aproximadamente un día antes de que comience cada solicitud, lo que dará como resultado una excepción del tipo java.nio.channels.ClosedByInterruptException.

Mi suposición es que la aplicación no está liberando identificadores de archivos y después de un día de uso continuo se agota y ya no puede continuar procesando solicitudes (cada solicitud requiere la lectura de múltiples archivos de cada nodo de cuadrícula). Hemos envuelto la mayoría de nuestras operaciones de E / S de archivos en clases como esta

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);
        }
    }
}

Creo que el problema es que este diseño no libera explícitamente el identificador de archivo, mi solución propuesta es agregar un método de finalización como este

    protected void finalize() throws Throwable
    {
        reader.close();
        super.finalize();   
    }

que hará esto explícitamente. La pregunta (finalmente) es si es probable que esto tenga algún efecto. ¿Las clases como java.io.BufferedReader ya tienen algún mecanismo para tratar este tipo de problema?

EDITAR: También es muy apreciado que aquí haya maneras de verificar si este es realmente el problema ... es decir, ¿hay alguna forma de consultar a una JVM en ejecución y preguntar sobre las asignaciones de los manejadores de archivos?

¿Fue útil?

Solución

No tiene mucho sentido anular finalize () . Si el manejador está recolectando y finalizando la basura, entonces también lo es la instancia de java.io.BufferedReader y se cerrará.

Es posible (según la especificación) que el identificador se recoja pero no se finalice, pero no es muy probable.

Puede intentar usar PhantomReference s para limpiar los manejadores de archivos no utilizados, pero supongo que sus instancias de BufferedReaderImpl todavía se referencian desde algún lugar (por ejemplo, los valores en un < code> Map de los nombres de archivo a los manejadores abiertos) y eso es lo que impide que se cierren (en cuyo caso los finalizadores no ayudarán).

Otros consejos

No se puede confiar en los finalizadores para ser llamados. No es un buen enfoque para la gestión de recursos. El constructo estándar en Java para esto es:

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

Es posible que desee envolver estos manejadores dentro de una clase, pero eso no es un enfoque sólido.

La especificación de Java dice que no garantiza que se ejecutará ' finalize () '. Tu código debe cerrar explícitamente FileReader .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top