Liberazione di handle di file java
Domanda
Abbiamo un'applicazione piuttosto grande e complessa scritta in Java in esecuzione sul pacchetto Gridgain. Il problema che sto riscontrando è che questa applicazione rimarrà lì elaborando le richieste per circa un giorno prima che ogni richiesta inizi a provocare un'eccezione di tipo java.nio.channels.ClosedByInterruptException.
La mia supposizione è che l'applicazione non rilasci handle di file e dopo un giorno di uso continuo si esaurisce e non può più continuare a elaborare le richieste (ogni richiesta richiede la lettura di più file da ciascun nodo della griglia). Abbiamo racchiuso la maggior parte delle operazioni di I / O dei file in classi come questa
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);
}
}
}
Penso che il problema sia che questo design non rilascia esplicitamente l'handle del file, la mia soluzione proposta è quella di aggiungere un metodo finalizzato come questo
protected void finalize() throws Throwable
{
reader.close();
super.finalize();
}
che lo farà esplicitamente. La domanda (finalmente) è se questo abbia probabilmente qualche effetto. Classi come java.io.BufferedReader hanno già un meccanismo per affrontare questo tipo di problema?
MODIFICA: Anche qui sarebbe molto apprezzato il modo di verificare se questo è effettivamente il problema ... ovvero c'è un modo per interrogare una JVM in esecuzione e chiedere informazioni sulle allocazioni di handle di file?
Soluzione
È inutile ignorare finalize ()
. Se l'handle sta ricevendo la spazzatura raccolta e finalizzata, lo è anche l'istanza di java.io.BufferedReader
e verrà chiusa.
È possibile (secondo le specifiche) che l'handle sia stato raccolto, ma non finalizzato, ma ciò non è molto probabile.
Potresti provare a usare PhantomReference
per ripulire gli handle di file non utilizzati, ma suppongo che le tue istanze di BufferedReaderImpl
siano ancora referenziate da qualche parte (ad es. valori in un < code> Map da nomi di file a handle aperti) e questo è ciò che impedisce loro di essere chiusi (nel qual caso i finalizzatori non aiuteranno.)
Altri suggerimenti
Non è possibile fare affidamento sui finalizzatori per essere chiamati. Non è un buon approccio per la gestione delle risorse. Il costrutto standard in Java per questo è:
InputStream in = null;
try {
in = ...;
// do stuff
} catch (IOException e) {
// error
} finally {
if (in != null) { try { in.close(); } catch (Exception e) { } }
in = null;
}
Potresti voler avvolgere questi handle all'interno di una classe, ma questo non è un approccio solido.
Le specifiche Java indicano che non è garantito che ' finalize ()
' verrà eseguito. Il tuo codice deve chiudere esplicitamente FileReader
tu stesso