Frage

Ich habe einen Speicherverlust Problem in meiner Anwendung, die Lasten eine große Menge von Bildern. Ich bin ziemlich neu in C # und dachte, meine Tage von Speicherverlust Fragen waren vorbei. Ich kann nicht herauszufinden, das Problem - vielleicht verwende ich einige nicht verwaltete Module, die ich nicht richtig behandeln werde?

Zu meinem Problem illustrieren Ich habe den Kern vereinfacht, was das Problem verursacht und bewegt diese in ein sauberes Projekt. Beachten Sie, dass das alles albern Code ist, die nicht die ursprüngliche Anwendung reflektiert es kam. In der Testanwendung habe ich 2 Tasten, die Auslösung zwei Ereignisse.

Button 1 - erstellen: ein Objekt in die Datacontext einstellen. Dadurch werden die Bilder laden und sie am Leben zu halten, indem das Objekt an die Datacontext Einstellung:

var imgPath = @"C:\some_fixed_path\img.jpg";
DataContext = new SillyImageLoader(imgPath);

Button 2 - CleanUp: Mein Verständnis ist, dass, wenn ich von der Referenz gehen lassen die SillyImageLoader hält, die wiederum die Bilder hält, dann wird diese gelöscht werden. I triggern auch explizit garbage collection nur sofort die Größe des Speichers, um zu sehen, nachdem die Referenz fallen.

DataContext = null; 
System.GC.Collect();

Bei der Prüfung, ich bin ein 974KB JPEG-Bild zu laden. Halten 30 Bitmap-Darstellungen dieser die Speicherauslastung von meiner Anwendung von ~ 18MB bis 562MB ~ steigert. Okay. Aber wenn ich Bereinigung traf der Speicher fällt nur auf ~ 292MB. Wenn ich erstellen + CleanUp wiederholen Ich bin mit einem anderen ~ 250 MB Speicherplatz zur Verfügung. So offensichtlich ist noch etwas von jemandem gehalten.

Hier ist der SillyImageLoader-Code:

namespace MemoryLeakTest
{
    using System;
    using System.Drawing;
    using System.Windows;
    using System.Windows.Interop;
    using System.Windows.Media.Imaging;

    public class SillyImageLoader
    {
        private BitmapSource[] _images; 

        public SillyImageLoader(string path)
        {
            DummyLoad(path);
        }

        private void DummyLoad(string path)
        {
            const int numberOfCopies = 30;
            _images = new BitmapSource[numberOfCopies];

            for (int i = 0; i < numberOfCopies; i++)
            {
                _images[i] = LoadImage(path);
            }
        }

        private static BitmapSource LoadImage(string path)
        {
            using (var bmp = new Bitmap(path))
            {
                return Imaging.CreateBitmapSourceFromHBitmap(
                    bmp.GetHbitmap(),
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }            
        }
    }
}

Irgendwelche Ideen? Das Problem scheint mit dem Bitmap zu sein. nur die Bitmap Holding gibt es kein Speicherleck. Ich bin mit Bitmap Lage sein, dies von einem Bild auf die Source-Eigenschaft einzustellen. Soll ich das anders machen? Wenn ja - ich würde immer noch wie die Antwort den Speicherverlust wissen.

Danke.

War es hilfreich?

Lösung

Wenn Sie anrufen

bmp.GetHbitmap()

eine Kopie des Bitmap erzeugt. Sie werden einen Verweis auf den Zeiger auf dieses Objekt und Anruf

halten müssen
DeleteObject(...)

auf sie.

hier :

  

Bemerkungen

     

Sie sind verantwortlich für den anruf   GDI DeleteObject Methode der freien   Speicher durch das GDI-Bitmap-Objekt verwendet wird.


Unter Umständen können Sie sich die Kopfschmerzen sparen (und Overhead) des Kopierens der Bitmap unter Verwendung von Bitmap statt Bitmapsource. Auf diese Weise können Sie in einem Schritt laden und erstellen.

Andere Tipps

Sie müssen die GDI DeleteObject Methode auf dem IntPtr Zeiger von GetHBitmap () zurückgegeben nennen. Die IntPtr aus dem Verfahren zurückgeführt ist, ein Zeiger auf die Kopie des Objekts in dem Speicher. Dies muss manuell mit dem folgenden Code befreit werden:

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

private static BitmapSource LoadImage(string path)
{

    BitmapSource source;
    using (var bmp = new Bitmap(path))
    {

        IntPtr hbmp = bmp.GetHbitmap();
        source = Imaging.CreateBitmapSourceFromHBitmap(
            hbmp,
            IntPtr.Zero,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions());

        DeleteObject(hbmp);

    }

    return source;
}

Es scheint, dass, wenn Sie GetHBitmap () aufrufen, sind Sie verantwortlich für die Freigabe des Objekts

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

private void DoGetHbitmap() 
{
    Bitmap bm = new Bitmap("Image.jpg");
    IntPtr hBitmap = bm.GetHbitmap();

    DeleteObject(hBitmap);
}

Ich vermute, dass die Bitmapsource übernehmen die Verantwortung nicht für dieses Objekt zu befreien.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top