2014-10-24 24 views
17

Ho un'esperienza audio nel linguaggio di programmazione Java. Ma una cosa che è sempre stata nella mia mente è perché è necessario close()java.io.InputStream o sue sottoclassi?Perché è bello chiudere() un inputstream?

Ora con java.io.OutputStream, dicono FileOutputStream, dopo aver scritto su un file, se non close() il flusso di output, i dati che abbiamo voluto scrivere nel file rimane nel buffer e non è scritto nel file.

Quindi diventa necessario close() un OutputStream. Ma non ho mai avuto esperienze amare dopo lo non chiudendo un InputStream.

Ma ancora tutti gli articoli su Internet e sui libri dicono che è sempre bene chiudere qualsiasi Stream potrebbe essere un InputStream o uno OutputStream.

Quindi la mia domanda è: perché è necessario a close() un InputStream? La gente dice che potresti trovarti di fronte a una perdita di memoria di te non close(). Quindi che tipo di perdita di memoria è quella?

+1

risorsa-fuga è probabilmente più di una preoccupazione qui. La gestione di inputstream richiede che il sistema operativo utilizzi le sue risorse e, se non lo si libera una volta che lo si utilizza, si esauriranno le risorse. – Andy

+0

In alcune JVM, il kernel sottostante manterrà aperto un FIS (come lo sottolineo) finché: A) non si chiude il flusso o B) si chiude la JVM. Altri flussi (specialmente quando si hanno a che fare con le prese) lasciano sapere altre cose quando hai finito. Ad esempio, chiudendo un OutStream da un Socket, si chiude anche il corrispondente inputstream sull'altro lato di Internet. – mailmindlin

+0

@mailmindlin No, non lo è. Nessun flusso si chiude automaticamente. Devi chiuderli da soli. – EJP

risposta

25

Un InputStream lega una piccola risorsa del kernel, un handle di file di basso livello. Inoltre, il file verrà bloccato in una certa misura (da eliminare, rinomina), a condizione che sia aperto per la lettura. Immaginiamo che non ti importa del file bloccato. Alla fine, se hai bisogno di leggere un altro file e aprirlo con un nuovo InputStream, il kernel assegna in sequenza un nuovo descrittore (flusso di file) per te. Questo si sommerà.

È solo una questione di tempo fino al fallimento del programma per un'applicazione di lunga durata.

La tabella del descrittore di file per un processore è di dimensioni limitate. Alla fine la tabella di gestione file avrà esaurito gli slot liberi per il processo. Anche a migliaia, puoi ancora facilmente esaurirlo per un'applicazione di lunga durata, a quel punto il tuo programma non può più aprire un nuovo file o socket.

Il processo di tabella di descrittore di file è semplicistico come qualcosa di simile:

IOHANDLE fds[2048]; // varies based on runtime, IO library, etc. 

Si inizia con 3 slot occupati. Riempi questo e hai eseguito un rifiuto di servizio su te stesso.

Quindi tutto questo è bello sapere; il modo migliore per applicarlo?

Se si fa affidamento su oggetti locali per uscire dal campo di applicazione, quindi fino al Garbage Collector, che può raccoglierlo nel suo momento dolce (non deterministico). Quindi non fare affidamento sul GC, chiudili esplicitamente.

Con Java, si desidera utilizzare try-with-resources sui tipi che implementano java.lang.AutoCloseable ", che include tutti gli oggetti che implementano java.io.Closeable" per la documentazione: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Con C#, l'equivalente è un 'blocco utilizzando' su oggetti che implementano IDisposable

+1

È chiuso quando è variabile locale e il metodo restituisce? Ofcourse supponendo che abbiamo usato solo ClassPathResource di primavera. – pinkpanther

+0

@pinkpanther - Avrai bisogno di usare try-with-resources per assicurarti che, altrimenti, rimanga fino al Garbage Collector quando li raccoglierà (non deterministici). https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html - Lo stesso vale per C# ma si usa l'istruzione using. – codenheim

3

Non si tratta di una memoria di memoria tanto quanto una perdita di gestione file. Il sistema operativo consentirà a un singolo processo di aprire un determinato numero di file e, se non si chiudono i flussi di input, potrebbe impedire alla JVM di aprirne altri.

+0

Sto parlando di un InputStream in generale. E non solo un FileInputStream. –

+1

@Aditya L'esempio originale con OutputStream utilizza un FileOutputStream per illustrare il motivo per cui deve essere chiuso, quindi perché questo sarebbe un esempio meno valido? :) –

+0

No, perché era per farti capire la mia domanda. Ma questa risposta è specifica per un FileInputStream. Mentre la mia domanda è per un InputStream in generale. :) –

2

Ci potrebbe essere un qualsiasi numero di risorse del sistema operativo associati a un InputStream, come i file aperti, o prese di corrente Un close() libererà queste risorse

Il tuo programma non ha bisogno di sapere che tipo di InputStream sta funzionando. Dovrebbe solo aderire al contratto che il flusso viene chiuso dopo l'uso, in modo che qualsiasi risorsa possa

3

È una potenziale perdita di risorse. nce rende impossibile sapere esattamente quale risorsa potrebbe essere trapelata quando poni la domanda in questo modo. Ad esempio, potrei scrivere la mia classe chiamata VoidInputStream che non assegna risorse che richiedono la chiusura. Ma ancora se non lo chiudi, stai violando il contratto ereditato.

Vedere http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html Per un elenco dei diversi flussi di input.

Il test per le risorse fuoriuscite è notoriamente difficile. Secondo solo al test per problemi di concorrenza. Non essere così sicuro di non aver inconsapevolmente causato un piccolo disastro.