12
votes

La classe Bitmap ne dispose pas de courant?

Alors, après avoir découvert que La classe BitMap s'attend à ce que le flux d'origine reste ouvert à la vie de l'image ou du bitmap , j'ai décidé de savoir si la classe BitMap ferme réellement le flux lorsqu'il est disposé.

Regarder le code source, Les classes bitmap et d'image créent une instance GPStream pour envelopper le flux, mais ne stockez pas une référence à l'instance GPStream ou à l'instance de diffusion forte>. P>

num = SafeNativeMethods.Gdip.GdipLoadImageFromStreamICM(new GPStream(stream), out zero);


5 commentaires

Ouais ... depuis que je suis tombé sur ce gâchis, je viens de cloner toutes les images que j'ouvre à l'aide de Lockbits et marshal.copy . À partir d'un bitmap créé sans aucune ressource liée est le seul moyen d'être sûr.


@Nyerguds C'est en fait une belle solution. Cependant, à ce stade, je recommanderais à ne pas utiliser l'API System.Drawing lorsque cela est possible. C'est juste une douleur dans le cul, spécialement en ce qui concerne la gestion de l'objet à vie et des fuites est si facile à créer accidentellement.


@Asasas bien, la gestion de l'objet n'est qu'une mentalité. Il est parfaitement possible d'être assez méticuleux pour ne jamais avoir de fuites de mémoire. Des langues comme c ++ n'ont rien comme la collection automatique des ordures de toute façon. Mais oui, system.Drawing est un peu montrant son âge ces jours-ci et n'est pas très universellement utilisable.


J'ai écrit imageflow.net pour éviter d'utiliser System.Drawing. Voir Github.com/imazen/imageflow-DotNet


@LilithRiver Eh bien, si vous utilisez Windows.Forms et souhaitez afficher des images dans des commandes Windows courantes, vous êtes toujours bloqué avec System.Drawing Quoi qu'il en soit ...


3 Réponses :


9
votes

Puisque vous fournissez le flux dans cet exemple, j'imagine que vous êtes responsable de la disposition.


7 commentaires

Exactement. Cela a été discuté avant - bitmap n'entraînant aucune responsabilité pour la durée de vie du flux. Et si vous vouliez faire autre chose avec le même flux après avoir joué avec bitmap? Vous seriez très déçu d'apprendre bitmap disposé pour vous.


Oui, si le constructeur a été fini avec le flux. Mais lorsqu'un objet "prend" un flux et l'utilise à des moments arbitraires, la propriété est transférée. Dans ce cas, seule la classe bitmap sait quand elle est "fait" avec le flux, et seule la classe BitMap peut être responsable de la fermeture.


Habituellement, un objet ferait une référence à son propre ruisseau, la tenant de la poubelle perçue aussi longtemps que nécessaire - mais ne le disposerait pas, car cela se traduirait par un code illisible et peut-être même pastraçable "arrive une fois dans une lune bleue " Bugs.


Idéalement, cela lirait tout en mémoire et vous pourriez disposer le flux immédiatement après sa lecture. Apparemment, il garde le flux ouvert lire des métadonnées à la demande. Assez mauvaise excuse.


Il ne parvient pas également à conserver une référence au flux, de sorte que le flux obtient des ordures recueillies lorsqu'il est toujours utilisé (puisque la référence est transmise par COM). Il y a eu des messages sur le problème.


Bitmap est une exception documentée à la règle, et peut-être une inutile - je ne suis pas en désaccord avec cela. Je suis en désaccord avec la perte de bitmap pour disposer du flux, ce qui en fait un objet encore pire pour travailler.


Eh bien, si l'un ou l'autre (a), cela pourrait le charger à 100% en mémoire au lieu de seulement 99% en mémoire, (b) ne pas être scellé , (c) offre un événement de disposition, (d) avoir une Boolean pour la fermeture du flux sur le dispositif, ou (e) Gardez simplement une référence à Stinkin 'à la diffusion à la diffusion de GC afin que GC fonctionne correctement, il serait beaucoup plus facile de travailler avec.



3
votes

C'est une bonne pratique pour avoir la méthode qui ouvre un flux, le fermez également. De cette façon, il est plus facile de garder une trace des fuites. Il serait assez étrange d'avoir un autre objet fermer le courant que vous avez ouvert.


3 commentaires

Transférer à la fois un bitmap et une instance de flux (facultatif) est plutôt douloureuse. En regardant toutes les API que j'ai vues, personne ne s'attend à ce comportement.


@ComputerLinglingLingLingLingLingLingLinglingLings - Si vous ressentez la nécessité de passer ces deux autour de votre conception, vous risquez de vous tromper. Dans un tel cas, j'essaierais de faire un objet (pas une seule méthode) responsable de l'ouverture et de la fermeture du flux.


Considérez que les flux eux-mêmes peuvent être configurés pour fermer le flux de parents et que Bitmap lui-même a un comportement en streaming.



0
votes

Parce que Bitmap ne peut garantir dans quel ordre le destructeur est appelé, il ne fermera pas le flux car il a peut-être déjà été fermé avec son propre destructeur lors de la collecte des ordures. Le CLR de Jeffrey Richter via C # a un chapitre sur la gestion de la mémoire qui explique avec beaucoup plus de clarté que possible.


1 commentaires

En fait, ça peut. Bitmap lancera des exceptions comestibles si vous fermez le flux sous-jacent avant de disposer du bitmap. Passez une mémoire Mémoire à une nouvelle instance Bitmap, attendez un peu, accédez au bitmap.Width et regardez les exceptions à voler.