2015-12-09 5 views
1

У меня есть простое приложение, которое отображает изображения и распечатывает их. Чтобы сделать его легким и удобным для проектирования, я использовал обычай Control.C# bitmaps вызывает утечку памяти

Теперь у меня есть простое управление размером 1800 х 2400 (да, довольно большой):

public class PhotoControl : UserControl 
{ 
    public PhotoControl() 
    { 
     InitializeComponent(); 
    } 
} 

И класс расширения, который использует его для генерации изображений:

public static class PhotoProcessor 
{ 
    private static readonly PhotoControl PhotoForm = new PhotoControl(); // Single instance 

    public static Image GenerateImage(this Photo photo) 
    { 
     PhotoForm.SetPhoto(photo); // Apply a photo 

     Image result; 

     using (Bitmap b = new Bitmap(PhotoForm.Width, PhotoForm.Height)) 
     { 
      Rectangle r = new Rectangle(0, 0, b.Width, b.Height); 
      PhotoForm.DrawToBitmap(b, r); // Draw control to bitmap 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       b.Save(ms, ImageFormat.Png); // Save bitmap as PNG 
       result = Image.FromStream(ms); 
      } 
     } 

     // GC.Collect(); 
     // GC.WaitForPendingFinalizers(); 

     return result; // return 
    } 

сейчас , Я пытаюсь сгенерировать 30 фотографий, используя это:

myPhoto.GenerateImage().Save(@"Output1.png", ImageFormat.Png); 
myPhoto.GenerateImage().Save(@"Output2.png", ImageFormat.Png); 

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

Это займет около 2 ГБ оперативной памяти, и, наконец, бросить исключение:

Необработанное исключение типа «System.OutOfMemoryException» произошло в System.Drawing.dll

Дополнительная информация: Out памяти.

Если я смотрю на визуальных диагностических инструментов Studio, это выглядит следующим образом:

enter image description here

Давайте сделать снимок, и посмотреть на содержимое кучи, то мы увидим, что есть много MemoryStream s:

enter image description here
enter image description here

Что вызывает MemoryStream для получения утечки памяти? Насколько я знаю, using() генерирует вызов Dispose(), который должен позаботиться об этом.

P.S. Если я удалю комментарий и позвоню GC.Collect(); GC.WaitForPendingFinalizers();, то он занимает в 2-3 раза меньше памяти, но он все равно растет - ~ 200 изображений все равно будут убивать приложение.

Изменение сохранения изображения на следующее:

Image img; 

img = myPhoto.GenerateImage(); 
img.Save(@"Output1.png", ImageFormat.Png); 
img.Dispose(); 

img = myPhoto.GenerateImage(); 
img.Save(@"Output2.png", ImageFormat.Png); 
img.Dispose(); 

будет производить один и тот же результат, что и использование GC.Collect();. Это также займет меньше памяти, но не устранит утечку памяти.

+2

Не нужно ли «Изображение» не удалять? Вы возвращаете его и никогда не удаляете – Rob

+1

@Rob Я догадался, что не хранить ссылку на изображение сделает GC собирать его. Во всяком случае, использование 'Dispose' после сохранения не решает проблему. Я обновил свой ответ. Спасибо. –

+1

Вы абсолютно уверены, что это место, которое создает проблему? Размер «MemoryStream» всегда один и тот же, но вы используете разные изображения (например, «Output1.png», 'Output2.png'). Может ли это быть какой-то другой «MemoryStream»? – Sinatr

ответ

2

Image инвентарь IDisposable и, следовательно, должен быть удален вручную. Вы в настоящее время возвращаете Image от GenerateImage, но не удаляете его после сохранения.

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