9
votes

Qu'advient-il d'une bufferedReader qui ne se fermait pas dans un appelable.call?

J'ai trois questions.

Pour expliquer, j'avais revu le code de quelqu'un, et remarquait que bufferedreader code> ne sont parfois pas fermés. Habituellement, Eclipse donne un avertissement selon lequel il s'agit d'une fuite de mémoire potentielle (et je le répare). Cependant, dans une classe interne appelable, il n'y a pas d'avertissement. P>

class outerClass {
    ...
    public void someMethod() {
        Future<Integer> future = outputThreadPool.submit(new innerClass(this.myProcess.getInputStream(), threadName));
        ...
    }

    class innerClass implements Callable<Integer> {
        private final InputStream stream;
        private final String prepend;

        innerClass(InputStream stream, String prepend) {
            this.stream = stream;
            this.prepend = prepend;
        }

        @Override
        public Integer call() {
            BufferedReader stdOut = new BufferedReader(new InputStreamReader(stream));
            String output = null;
            try {
                while ((output = stdOut.readLine()) != null) {
                    log.info("[" + prepend + "] " + output);
                }

            } catch (IOException ignore) {
            // I have no idea why we're ignoring this... :-|        
            }
            return 0;   
        }
    }
}


4 commentaires

Ne signalez pas que l'avertissement semble plus semblable à un bug éclipse qu'une décision consciente de dire «il est correct de le faire dans ce cas»


J'ai quelques réponses qui semblent se contredire mutuellement. D'une part, des gens disent que la bufferreader doit être fermée. D'autre part, ils disent que cela ne devrait pas être fermé car la fermeture fermerait l'introuvream it wraps et la classe d'appel pourrait en avoir besoin ...


Voir Cette question . Si une ressource comme un introuvable est transmise à une méthode, cela signifie que quelqu'un d'autre l'a ouvert, alors que quelqu'un d'autre devrait la fermer aussi. S'ils transmettent un flux sur votre méthode, essayez ensuite de l'utiliser ailleurs, il se briserait car il serait fermé (la fermeture d'un bufferreader ferme son flux), même si votre méthode pourrait avoir besoin faire une chose avec le ruisseau.


Jetez un coup d'œil à mes modifications à ma réponse.


5 Réponses :


1
votes

buffereddreader Fermer ()

ferme ce flux et libère toutes les ressources système associées à ce. Si le flux est déjà fermé, invoquer cette méthode n'a pas de effet.

Donc, si vous ne fermez pas (), les ressources système peuvent être toujours associées au lecteur qui peuvent provoquer une fuite de mémoire.

Pourquoi Eclipse ne mettant pas en surbrillance: il ne s'agit pas d'erreur de temps si vous ignorez appelant fermer (), donc Eclipse ne met pas en évidence.


3 commentaires

Ok qui répond en partie à la question 3 ... que je comprends. Mais, si c'est à l'intérieur d'un fil, je peux peut-être quand le fil est sorti, il serait des ordures collectées?


Oui, seul l'objet bufferedreader peut être gisé, mais d'autres éléments liés à la prise, je ne pense pas que GC fait quelque chose pour cela.


Mais Eclipse fait le souligne quand ce n'est pas dans une classe intérieure ... c'est ce qui me déroule.



7
votes

Je dirais que puisque ils créent un bufferedreader CODE> autour d'un InputStream code>, le code n'est pas sécuritaire d'appeler ferme () code>. Le code qui appelle fermer () code> doit toujours être le code qui crée le flux et effectué à l'aide d'essayer / enfin. xxx pré>

Une autre note: Votre code semble être enregistré production d'un autre processus. Vous ne seriez probablement pas capable de fermer le ruisseau de toute façon. Sans le tester moi-même, je ne suis pas sûr de ce qui se passerait si vous avez fermé un flux d'un autre processus. P>

OH, et le ioException code> n'est pas probable que le flux vient d'un autre processus. Ce n'est pas susceptible de se produire, sauf si une erreur irrécupérable se produit. Cela ne serait toujours pas une mauvaise idée de se connecter à l'exception en quelque sorte, cependant. P>


Modifier pour répondre à votre commentaire sur les réponses mixtes: strong> P>

Utilisons un flux de sortie et bufferedwriter code > à titre d'exemple cette fois: p> xxx pré>

cela fonctionne. La méthode writeine ​​est utilisée comme délégué à créer écrivain code> et à écrire un seul ligne code> dans le fichier. Bien sûr, cette logique pourrait être quelque chose de plus complexe, tel que transformer un objet dans une chaîne code> et l'écrire. Cela rend la méthode MAIN code> un peu plus facile à lire également. P>

Maintenant, si c'était à la place, nous avons fermé la bufferedWriter? P>

private static void writeLine(OutputStream stream, String line) throws IOException {
    BufferedWriter writer = null;
    try {
        writer = new BufferedWriter(new InputStreamWriter(stream));
        writer.write(line + NEWLINE);
    } finally {
        if (writer != null)
            writer.close();
    }
}


3 commentaires

Vous êtes ... Je suis allé chercher à l'endroit où le ruisseau était en fait créé ... beaucoup plus en amont dans le code; et il est fermé là-bas. Merci!


Aussi à propos de la sortie de la journalisation d'un autre processus. Ce processus faisait du travail sur le dossier étant diffusé par le flux en question et il était important de suivre toutes les erreurs potentielles ou problèmes dans les journaux.


Aussi génial et merci pour la réponse plus détaillée. Vous étiez plus d'aide que mon responsable de devis qui supervise le code en question au moment de la rédaction :)



1
votes

Peu importe où vous ouvrez le flux, vous devez le fermer dans le bloc enfin et c'est une bonne pratique pour tester le flux pour null code>, car si le fichier n'existime pas le flux Soyez NULL code>, une exception sera lancée ( filenotfoundexception code>) mais le bock enfin est terminé. C'est à dire. Le contenu de la méthode d'appel devrait être le suivant:

   BufferedReader stdOut = null;
   String output = null;
        try {
            stdOut = new BufferedReader(new InputStreamReader(stream));
            while ((output = stdOut.readLine()) != null) {
                log.info("[" + prepend + "] " + output);
            }
        } catch (FileNotFoundException ex) {
            log.warn("Unable to open nonexisten file " + whichOne);  
        } catch (IOException ex) {
            log.warn("Unable to read from stream");  
        } finally {
            if (stdOut != null) {
                try {
                   stdOut.close();
                } catch (IOException e) {
                    log.warn("Unable to close the stream");
                }
            }
        }
        return 0;


3 commentaires

stdout ne peut jamais être égal à NULL, il n'ya donc aucun point dans le bloc IF avant la fermeture. Si la construction a échoué, elle n'atteindra jamais le blocage enfin.


Oh, tu as raison. Je l'ai édité légèrement. Maintenant, c'est correct.


À peu près sûr que nous ne allons pas aller à n'importe 7 fois bientôt :(



2
votes

Vous ne voulez peut-être pas fermer le bufferedreader dans ce cas. Le introuvable qui a été transmis au constructeur est l'objet qui peut être associé à une ressource système. Le bufferedreader et le INPUTStreamReader ne sont que des emballages autour de cela. Fermer le bufferedreader fermerait également le introuvable , ce qui pourrait ne pas être ce que l'appelant souhaitait.


0 commentaires

1
votes
  1. ne met pas en surbrillance et c'est vrai, car un flux peut être fermé quelque part ailleurs hors de la méthode d'appel.

  2. S'il est fermé dans la méthode d'appel que d'autres threads peuvent l'utiliser pour le moment.

  3. avec le bufferdrreader rien que si vous perdez la référence au flux et ne pouvez pas la fermer et cela conduit à une fuite de mémoire.


0 commentaires