У меня есть простое приложение, которое отображает изображения и распечатывает их. Чтобы сделать его легким и удобным для проектирования, я использовал обычай 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, это выглядит следующим образом:
Давайте сделать снимок, и посмотреть на содержимое кучи, то мы увидим, что есть много MemoryStream
s:
Что вызывает 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();
. Это также займет меньше памяти, но не устранит утечку памяти.
Не нужно ли «Изображение» не удалять? Вы возвращаете его и никогда не удаляете – Rob
@Rob Я догадался, что не хранить ссылку на изображение сделает GC собирать его. Во всяком случае, использование 'Dispose' после сохранения не решает проблему. Я обновил свой ответ. Спасибо. –
Вы абсолютно уверены, что это место, которое создает проблему? Размер «MemoryStream» всегда один и тот же, но вы используете разные изображения (например, «Output1.png», 'Output2.png'). Может ли это быть какой-то другой «MemoryStream»? – Sinatr