web-dev-qa-db-fra.com

Pourquoi est-il bon de fermer () un flux d'entrée?

J'ai une solide expérience en Java. Mais une chose qui a toujours été dans mon esprit, c'est pourquoi est-il nécessaire de close()Java.io.InputStream ou ses sous-classes?

Maintenant avec Java.io.OutputStream, disons FileOutputStream, après avoir écrit dans un fichier, si nous ne close() le flux de sortie, les données que nous avions l'intention d'écrire dans le fichier restent dans le tampon et n'est pas écrit dans le fichier.

Il devient donc nécessaire de close() un OutputStream. Mais je n'ai jamais eu d'amères expériences après ne ferme pas un InputStream.

Mais tous les articles sur Internet et les livres disent toujours qu'il est toujours bon de fermer n'importe quel Stream, qu'il s'agisse d'un InputStream ou d'un OutputStream.

Ma question est donc la suivante: pourquoi devient-il nécessaire de close() un InputStream? Les gens disent que vous pourriez faire face à une fuite de mémoire si vous ne le faites pas close(). Alors, quel genre de fuite de mémoire est-ce?

34
Aditya Singh

Un InputStream lie une minuscule ressource de noyau, un descripteur de fichier de bas niveau. De plus, le fichier sera verrouillé dans une certaine mesure (de la suppression, du changement de nom), tant que vous l'avez ouvert pour la lecture. Imaginons que vous ne vous souciez pas du fichier verrouillé. Finalement, si vous devez lire un autre fichier et l'ouvrir avec un nouveau InputStream, le noyau alloue séquentiellement un nouveau descripteur (flux de fichiers) pour vous. Cela va s'additionner.

Ce n'est qu'une question de temps avant l'échec du programme pour une application de longue durée.

La table de descripteurs de fichiers pour un processeur est de taille limitée. Finalement, la table des descripteurs de fichiers manquera d'emplacements libres pour le processus. Même par milliers, vous pouvez toujours l'épuiser facilement pour une application de longue durée, auquel cas, votre programme ne peut plus ouvrir un nouveau fichier ou socket.

La table des descripteurs de fichiers de processus est aussi simpliste que quelque chose comme:

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

Vous commencez avec 3 emplacements occupés. Remplissez-le et vous vous êtes fait dénier de service.

Donc tout cela est agréable à savoir; comment l'appliquer au mieux?

Si vous comptez sur des objets locaux pour sortir de la portée, alors c'est au garbage collector, qui peut le récolter dans son propre temps doux (non déterministe). Ne vous fiez donc pas au GC, fermez-les explicitement.

Avec Java, vous souhaitez utiliser try-with-resources sur les types qui implémentent Java.lang.AutoCloseable ", qui inclut tous les objets qui implémentent Java.io.Closeable" selon les documents: https://docs.Oracle .com/javase/tutorial/essential/exceptions/tryResourceClose.html

Avec C #, l'équivalent est un bloc "using" sur les objets qui implémentent IDisposable

41
codenheim

Ce n'est pas une fuite mémoire autant qu'une fuite de descripteur de fichier. Le système d'exploitation n'autorisera qu'un seul processus à ouvrir un certain nombre de fichiers, et si vous ne fermez pas vos flux d'entrée, il pourrait empêcher la JVM de s'ouvrir davantage.

8

C'est une fuite potentielle de ressources. L'héritage rend impossible de savoir exactement quelle ressource pourrait être divulguée lorsque vous posez la question de cette façon. Par exemple, je pourrais écrire ma propre classe appelée VoidInputStream qui n'alloue aucune ressource nécessitant une fermeture. Mais toujours si vous ne le fermez pas, vous violez le contrat hérité.

Voir http://docs.Oracle.com/javase/7/docs/api/Java/io/InputStream.html Pour une liste des différents flux d'entrée.

Il est notoirement difficile de tester les ressources perdues. En second lieu seulement pour tester les problèmes de concurrence. Ne soyez pas si sûr que vous n'avez pas causé sans le savoir un peu de ravage.

5
candied_orange

Il peut y avoir un certain nombre de ressources de système d'exploitation associées à un InputStream, comme des fichiers ouverts ou des sockets. Un close () libérera ces ressources.

Votre programme n'a pas besoin de savoir avec quel type de InputStream il travaille. Il doit simplement respecter le contrat que le flux est fermé après utilisation, afin que toutes les ressources puissent être libérées.

2
Thomas Stets