Liberando identificadores de arquivo java
Pergunta
Nós temos uma aplicação bastante grande e complexo escrito em Java que é executado no topo do pacote Gridgain. O problema que estou tendo é que esta aplicação vai sentar-se lá o processamento de pedidos por aproximadamente um dia antes de cada pedido começa resultando em uma exceção do tipo java.nio.channels.ClosedByInterruptException.
A minha suposição é que o aplicativo não está liberando identificadores de arquivo e depois de um dia de uso contínuo que se esgote e já não pode continuar a processar pedidos (cada pedido requer a leitura de vários arquivos de cada nó da rede). Temos envolveu a maioria das nossas operações de arquivo IO nas aulas, como um presente
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);
}
}
}
Eu acho que o problema é que este projeto não libera explicitamente o identificador de arquivo, a minha solução proposta é adicionar um método finalize como este
protected void finalize() throws Throwable
{
reader.close();
super.finalize();
}
que irá fazer isso explicitamente. A pergunta (finalmente) é se este é ou não provável que tenha qualquer efeito. Fazer classes como java.io.BufferedReader já tem algum mecanismo para lidar com este tipo de problema?
EDIT:? Também muito apreciada aqui seria formas de verificar se este é realmente o problema ... ou seja, há uma maneira para consultar uma JVM em execução e perguntar sobre isso de alocações de identificador de arquivo
Solução
Há pouco ponto em substituir finalize()
. Se a alça está sendo coletado e finalizado, então que é a instância de java.io.BufferedReader
e ele vai ficar fechado.
É possível (de acordo com a especificação) que a alça está sendo lixo coletado, mas não finalizado, mas isso não é muito provável.
Você pode tentar usar PhantomReference
s para limpar identificadores de arquivos não utilizados, mas meu palpite é que suas instâncias do BufferedReaderImpl
ainda são referenciados de algum lugar (por exemplo, valores em um Map
de nomes para identificadores abertos) e que é o que está impedindo-os de serem fechada (em que finalizadores caso não vai ajudar.)
Outras dicas
Finalizadores não pode ser invocado para ser chamado. Não é uma boa abordagem para a gestão de recursos. A construção padrão em Java para isso é:
InputStream in = null;
try {
in = ...;
// do stuff
} catch (IOException e) {
// error
} finally {
if (in != null) { try { in.close(); } catch (Exception e) { } }
in = null;
}
Você pode querer embrulhar estas alças dentro de uma classe, mas isso não é uma abordagem robusta.
especificação Java diz que não é garantia de que 'finalize()
' será executado. Seu código deve explicitamente perto FileReader
si mesmo.