2010-03-11 2 views
4

У меня есть несколько изображений, которые я загружаю в ListBox в моем приложении WPF. Первоначально я использовал GDI для изменения размеров изображений (оригиналы занимают слишком много памяти). Это было прекрасно, за исключением того, что они занимали около 400 мс на изображение. Не так хорошо. Поэтому в поисках другого решения я нашел метод, который использует TransformedBitmap (который наследуется от BitmapSource). Это здорово, подумал я, я могу это использовать. За исключением я теперь получаю утечки памяти где-то ...Утечка памяти при асинхронной загрузке изображений BitmapSource

Я загрузки изображения асинхронно с помощью BackgroundWorker так:

BitmapSource bs = ImageUtils.ResizeBitmapSource(ImageUtils.GetImageSource(photo.FullName)); 
       //BitmapSource bs = ImageUtils.GetImageSource(photo.FullName); 
       bs.Freeze(); 

       this.dispatcher.Invoke(new Action(() => { photo.Source = bs; })); 

GetImageSource просто получает Bitmap с пути, а затем превращается в BitmapSource.

Вот фрагмент кода для ResizeBitmapSource:

const int thumbnailSize = 200; 
     int width; 
     int height; 

     if (bs.Width > bs.Height) 
     { 
      width = thumbnailSize; 
      height = (int)(bs.Height * thumbnailSize/bs.Width); 
     } 
     else 
     { 
      height = thumbnailSize; 
      width = (int)(bs.Width * thumbnailSize/bs.Height); 
     } 

     BitmapSource tbBitmap = new TransformedBitmap(bs, 
                  new ScaleTransform(width/bs.Width, 
                       height/bs.Height, 0, 0)); 

     return tbBitmap; 

Этот код, по существу код из: http://rongchaua.net/blog/c-wpf-fast-image-resize/

Любые идеи, что может быть причиной утечки?

редактировать: Вот код для GetImageSource, в соответствии с просьбой

using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) 
      { 
       using (var bmp = Image.FromStream(stream, false, false)) 
       { 
        // Use WPF to resize 
        var bitmapSource = ConvertBitmapToBitmapSource(bmp); 
        bitmapSource = ResizeBitmapSource(bitmapSource); 
        return bitmapSource; 
       } 
      } 
+0

Как вы диагностировали утечку? И почему вы думаете, что это в этом коде, а не, например, GetImageSource()? –

+0

BitmapSource, который я использую в элементе управления WPF, изменен правильно, но, глядя на память, используемую процессом, он использует ту же память, что и изображение полного размера. Поэтому где-то вдоль линии полноразмерный BitmapSource не удаляется. edit: и потому, что GetImageSource на самом деле не меняется. Если я захочу изменить размер с помощью GDI, это нормально. Но когда я изменяю размер с помощью этого метода TransformedBitmap, он не работает. – Harry

+1

Не могли бы вы попросить ручной GC, чтобы узнать, выпущена ли память? Если нет, у вас, скорее всего, есть ссылка где-то, где хранится память. –

ответ

4

Я думаю, вы неправильно поняли, как работает TransformedBitmap. Он содержит ссылку на исходное растровое изображение и преобразует его в память. Возможно, вы можете закодировать преобразованное растровое изображение в поток памяти и прочитать его обратно. Я не уверен, насколько это было бы быстро, но тогда вы не удержитесь от полноразмерного растрового изображения.

Я нашел это blog post, который возвратил WriteableBitmap с TransformedBitmap в качестве источника. WriteableBitmap скопирует данные пикселя в буфер памяти в инициализаторе, поэтому он фактически не удерживает ссылку на TransformedBitmap или полноразмерное изображение.

+0

Хорошо, я думаю, что понимаю вас. Я попробую это утром, спасибо. – Harry

1

В догадке, глядя на ваш код, который вы, возможно, придется утилизировать битмапа, возвращенного вызовом ImageUtils.GetImageSource (фото. Полное имя).

Я также отметил в блоге, что вы указали, что автор добавил обновление (11 марта) о вставке оператора using, чтобы предотвратить утечку памяти.

+0

Да, это было основано на комментарии, который я добавил. Однако это не работает. Не сказать, что его код неверен, но в моем есть что-то, что заставляет его уйти .. awry ... – Harry

Смежные вопросы