Утечка памяти растрового изображения и hBitmap - PullRequest
2 голосов
/ 24 октября 2011

Я снимаю изображения с моей веб-камеры для управления изображениями в WPF с помощью WebCam_Capture.dll. Для каждого захваченного кадра у меня есть событие с именем webCam_imageCaptured. Он звонит каждый раз, когда я получаю новое изображение с веб-камеры. В этом случае я вызываю метод LoadBitmap для получения hBitmap и получения BitmapSource для помещения этого захваченного изображения в элемент управления Image. Вот код этого метода:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr handle);
public BitmapSource bs;
public IntPtr ip;
public BitmapSource LoadBitmap(System.Drawing.Bitmap source)
{
   ip = source.GetHbitmap();
   bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ip, IntPtr.Zero, System.Windows.Int32Rect.Empty,
   System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
   DeleteObject(ip);
   return bs;
}

А вот и код мероприятия:

private void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
    //_frameImage is Image WPF control.
     _frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);   
}

И у меня есть утечка здесь! ОЗУ загружается до 1 ГБ, а иногда и больше! DeleteObject(ip) работает не каждый раз, когда звонил. Когда объем оперативной памяти составляет 1 ГБ или более, он освобождает или показывает ошибку «Недостаточно памяти». Как это решить?

1 Ответ

2 голосов
/ 25 октября 2011

Без помощи профилировщика или даже просмотра остальной части вашего кода, я почти гарантирую, что здесь «утечка»:

_frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);

Этот метод, безусловно, вызывается очень быстро, и выне Dispose() в вашем Bitmaps.У GC не будет времени, чтобы привести себя в порядок после вас и вызывать финализатор на каждом Bitmap, поэтому у вас заканчивается память.

Вам нужно позвонить Dispose() на этот Bitmap после того, как выс этим покончено.BitmapSource в любом случае создает копию данных изображения, поэтому в этом нет необходимости.Я бы попробовал это:

private void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
    using( Bitmap b = e.WebCamImage )
    {
         _frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);   
    }
}

Это, конечно, предполагает, что удаление растрового изображения внутри этого обработчика событий является допустимым (например, кто-нибудь еще обрабатывает это событие?). Возможно, вы захотите выставитьВместо этого BitmapSource в классе WebCamEventArgs, чтобы вы могли убедиться, что другие клиенты не полагаются на то, что Bitmap остается действительным.

Это, конечно, если вы написали API, чтобы быть с.Если нет, вы можете написать оболочку, чтобы убедиться, что ваш код никогда не видит Bitmap и работает только с типами изображений WPF.

...