7

Esiste un buon esempio per dimostrare la perdita di descrittori di file in Android? Ho letto da qualche parte che si verifica se non chiudiamo i flussi ad esempio FileInputStream o FileOutputStream ma non sono riuscito a trovare alcun buon esempio di riferimento che lo dimostrasse.Esempio di perdita di descrittore di file?

Si prega di condividere alcuni blog/snippet di codice. grazie!

+1

Basta aprire un gruppo di file o porte senza chiudere? Dopo alcune migliaia di finestre si interrompe dando loro. Simile in altri sistemi operativi. – Ordous

+0

@Ordous, grazie per la tua rapida risposta. Potresti per favore postare un frammento di codice funzionante di esso – VicJordan

risposta

0
InputStream in; 
try { 
    in = new BufferedInputStream(socket.getInputStream()); 

    // Do your stuff with the input stream 
} catch (Exception e) { 
    // Handle your exception 
} finally { 
    // Close the stream here 
    if (in != null) { 
     try { 
      in.close(); 
     } catch (IOException e) { 
      Log.e(TAG, "Unable to close stream: " + e); 
     } 
    } 
} 

L'idea è quella di chiudere il descrittore di file nel blocco finally. Sia che tu finisca con successo o che si verifichi un'eccezione, il descrittore di file sarà correttamente chiuso.

Ora, se siete alla ricerca di qualcosa da dimostrare come si esegue questa operazione correttamente, basta avvolgere questo codice in un ciclo while(1), commentare la riga in.close(), e mettere un break; nel blocco catch in modo che quando soffia uscirai dal tuo ciclo infinito.

+0

1) Questa domanda è chiamata "Esempio di perdita di descrittore di file", non "come chiudere correttamente i flussi". Non lo stai nemmeno facendo nel modo migliore.2) * avvolgere questo codice in un istante (1) loop * non si qualifica come una "fuga" (come in "perdita permanente accidentale di risorse") 3) C'è una buona probabilità che la creazione di traccia dello stack venga seguita da un pass GC, che finalizzerà rapidamente la maggior parte dei flussi "trapelati". – user1643723

+1

Mi dispiace, credo di non aver capito la tua domanda. Tuttavia, considerando che hai avuto questa domanda per un mese, con una taglia, e nessuno ha risposto, probabilmente non sono l'unica a non capire cosa stai chiedendo. Buona fortuna a te. – Joboodi

-1
InputStream in; 

try { 

    in = new FileInputStream(new File("abc"); 


    in.read(); // Do some stuff with open fileinputstream 
    // If an exception is generated, inputstream object will not be closed 
    // as the next statement will not be executed, instead jumping to 
    // the catch block. this will cause a leak of the fd assigned to file 
    // "abc" while opening it 
    in.close()' 
    } catch (Exception e) { 

    // Handle your exception 

    } 
6

A causa di Dalvik FileInputStream volontà close itself when it is garbage collected (questo vale anche per OpenJDK/Oracle) è meno comune di quanto si potrebbe pensare a perdere realmente descrittori di file. Ovviamente, i descrittori dei file verranno "filtrati" fino a quando il GC non verrà eseguito, quindi a seconda del programma potrebbe essere necessario un po 'di tempo prima che vengano recuperati.

Per realizzare una perdita più permanente, è necessario impedire che il flusso venga raccolto in modo irregolare, conservando un riferimento ad esso nella memoria.

Ecco un breve esempio che carica un file di proprietà ogni 1 secondo e tiene traccia di tutti i tempi è cambiato:

public class StreamLeak { 

    /** 
    * A revision of the properties. 
    */ 
    public static class Revision { 

     final ZonedDateTime time = ZonedDateTime.now(); 
     final PropertiesFile file; 

     Revision(PropertiesFile file) { 
      this.file = file; 
     } 
    } 

    /* 
    * Container for {@link Properties} that implements lazy loading. 
    */ 
    public static class PropertiesFile { 

     private final InputStream stream; 
     private Properties properties; 

     PropertiesFile(InputStream stream) { 
      this.stream = stream; 
     } 

     Properties getProperties() { 
      if(this.properties == null) { 
       properties = new Properties(); 
       try { 
        properties.load(stream); 
       } catch(IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      return properties; 
     } 

     @Override 
     public boolean equals(Object o) { 
      if(o instanceof PropertiesFile) { 
       return ((PropertiesFile)o).getProperties().equals(getProperties()); 
      } 
      return false; 
     } 
    } 

    public static void main(String[] args) throws IOException, InterruptedException { 
     URL url = new URL(args[0]); 
     LinkedList<Revision> revisions = new LinkedList<>(); 
     // Loop indefinitely 
     while(true) { 
      // Load the file 
      PropertiesFile pf = new PropertiesFile(url.openStream()); 
      // See if the file has changed 
      if(revisions.isEmpty() || !revisions.getLast().file.equals(pf)) { 
       // Store the new revision 
       revisions.add(new Revision(pf)); 
       System.out.println(url.toString() + " has changed, total revisions: " + revisions.size()); 
      } 
      Thread.sleep(1000); 
     } 
    } 
} 

A causa della lazy loading Manteniamo il InputStream nel PropertiesFile che verrà mantenuto ogni volta che creiamo una nuova Revisione e dal momento che non chiudiamo mai il flusso, qui verranno filtrati i descrittori di file.

Ora, questi descrittori di file aperti saranno chiusi dal sistema operativo quando il programma termina, ma fino a quando il programma è in esecuzione continuerà a perdere i descrittori di file come si può vedere, utilizzando lsof:

$ lsof | grep pf.properties | head -n 3 
java 6938 raniz 48r  REG 252,0 0 262694 /tmp/pf.properties 
java 6938 raniz 49r  REG 252,0 0 262694 /tmp/pf.properties 
java 6938 raniz 50r  REG 252,0 0 262694 /tmp/pf.properties 
$ lsof | grep pf.properties | wc -l  
431 

E se si forza il GC per eseguire possiamo vedere che la maggior parte di questi sono tornati:

$ jcmd 6938 GC.run 
6938: 
Command executed successfully 
$ lsof | grep pf.properties | wc -l 
2 

i restanti due descrittori sono quelli memorizzati nei revisione s.

Ho eseguito questo sulla mia macchina Ubuntu ma l'output sarebbe simile se eseguito su Android.

Problemi correlati