50 votes

WPF CreateBitmapSourceFromHBitmap fuite de mémoire

J'ai besoin de dessiner une image pixel par pixel et de l'afficher à l'intérieur d'un WPF. J'essaie de le faire à l'aide d'un Système.De dessin.Bitmap, puis en utilisant CreateBitmapSourceFromHBitmap pour créer un BitmapSource pour WPF contrôle de l'Image. J'ai une fuite de mémoire quelque part parce que lors de la CreateBitmapSourceFromBitmap est appelé à plusieurs reprises la mémoire monte et ne descend pas jusqu'à ce que la demande est terminée. Si je n'appelle pas CreateBitmapSourceFromBitmap il n'y a pas de changement notable dans l'utilisation de la mémoire.


            for (int i = 0; i < 100; i++)
            {
                System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1000, 1000);
                var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                source = null;
                bmp.Dispose();
                bmp = null;
            }

Que puis-je faire pour libérer de la BitmapSource de la mémoire?

86voto

Julien Lebosquain Points 20894

MSDN indique que, pour Bitmap.GetHbitmap(): Vous êtes responsable de l'appel du GDI DeleteObject méthode pour libérer la mémoire utilisée par le GDI objet bitmap. Il faut donc utiliser le code suivant:

// at class level
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

// your code
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1000, 1000)) 
{
    IntPtr hBitmap = bmp.GetHbitmap(); 

    try 
    {
        var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
    }
    finally 
    {
        DeleteObject(hBitmap)
    }
}

J'ai aussi remplacé votre Dispose() appel par un using déclaration.

23voto

Schneider Points 3812

Chaque fois que de traiter avec non géré poignées, il peut être une bonne idée d'utiliser la "sécurité de la poignée" wrappers:

public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    [SecurityCritical]
    public SafeHBitmapHandle(IntPtr preexistingHandle, bool ownsHandle)
        : base(ownsHandle)
    {
        SetHandle(preexistingHandle);
    }

    protected override bool ReleaseHandle()
    {
        return GdiNative.DeleteObject(handle) > 0;
    }
}

Construire un, comme dès que vous la surface de la poignée (idéalement, votre Api ne serait jamais exposer IntPtr, ils seraient toujours retourner sûr poignées):

IntPtr hbitmap = bitmap.GetHbitmap();
var handle = new SafeHBitmapHandle(hbitmap , true);

Et de l'utiliser comme ceci:

using (handle)
{
  ... Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(), ...)
}

Le SafeHandle de la base de donne vous une automatique jetable/finaliseur modèle, tout ce que vous devez faire est de remplacer le ReleaseHandle méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X