#c# #.net #winforms #memory-leaks
#c# #.net #winforms #утечки памяти
Вопрос:
Я создал короткую тестовую программу для непрерывного поворота изображения .jpg в форме, начиная с этого примера:
private void DrawImagePointF(PaintEventArgs e)
{
// Create image.
Image newImage = Image.FromFile("SampImag.jpg");
// Create point for upper-left corner of image.
PointF ulCorner = new PointF(100.0F, 100.0F);
// Draw image to screen.
e.Graphics.DrawImage(newImage, ulCorner);
}
Я знаю, что это может быть довольно необычный способ поворота изображения, но код работает так, как ожидалось — единственная проблема заключается в утечке памяти при каждом тике таймера, и я хотел бы понять причину и как ее избежать.
Это код, вызывающий утечку памяти:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Picture_rotation {
public partial class Form1 : Form {
Image jpg;
float angle = 0f;
PointF ulCorner = new PointF(50f, 50f);
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
jpg = Image.FromFile("picture.jpg");
}
private void DrawImagePointF(PaintEventArgs e) {
((Bitmap)jpg).SetResolution(e.Graphics.DpiX, e.Graphics.DpiY);
e.Graphics.DrawImage(Rotate(jpg, angle), ulCorner);
}
// interval = 100
private void timer1_Tick(object sender, EventArgs e) {
angle = angle % 360;
Invalidate(); // to invoke Form1_Paint()
}
private Bitmap Rotate(Image original, float angle) {
Bitmap bmp = new Bitmap(original.Width, original.Height);
Graphics g = Graphics.FromImage(bmp);
g.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
g.RotateTransform(angle);
g.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(original, new Point(0, 0));
g.Dispose();
return bmp; // memory leak?
}
private void Form1_Paint(object sender, PaintEventArgs e) {
DrawImagePointF(e);
}
}
}
Комментарии:
1. Вы удаляете растровое изображение в какой-то момент? или просто создавать кучу и не беспокоиться об этом?
2. Проблема с материалом, имеющим неуправляемую память, заключается в том, что, хотя он использует память, GC ее не видит. Для них эти экземпляры (изображение, растровое изображение) КРОШЕЧНЫЕ — очень маленькие. В основном указатель на неуправляемую память. Следовательно, IDisposable — в КАКОЙ-ТО МОМЕНТ сработает GC. Это может произойти, когда управляемая память достигает 1 ГБ, что может произойти, когда общая память программы достигает десятков ГБ.
3. Утилизируйте экземпляр BitMap, возвращенный
Rotate
после его использования4.
using var bmp = Rotate(jpg, angle);
всегда используйте оператор using, когда это возможно. Это создает pesudo, наконец, в IL, и такое будет удаляться, даже если есть исключение. тогда меньше строк кода, попробуйте наконец, легко поддерживать и легче читать намерение5. Вы должны утилизировать все, что имеет dispose. Обычно это указывает на то, что он обрабатывает и обрабатывает неуправляемые ресурсы, дополнительно позволяет вам неявно контролировать его жизненный цикл, и вам не нужно полагаться на неопределенный характер сборщика мусора, который, в свою очередь, будет запускаться, когда ему захочется, так, как ему хочется.
Ответ №1:
Вы уверены, что есть утечка памяти?
Если вы создаете много изображений / растровых изображений, не удаляя их, они будут загромождать вашу память. Но в конечном итоге сборщик мусора их соберет.
Объем памяти вашего приложения увеличится до 2? ГБ, а затем сжимается до 200? МБ после каждого GC.
Комментарии:
1. Если вы создаете много растровых изображений и не удаляете их, вам понравится ошибка GDI out of memory достаточно скоро
2. Да, вы были правы. GC действительно очищает память примерно через 5 минут, когда использование ОЗУ составляет около 2,5 ГБ, а затем оно возвращается к 20-30 МБ, и все начинается сначала. Я не пробовал, освобождал ли GC оперативную память раньше при запуске, например, 10 экземпляров программы с 16 ГБ оперативной памяти. Однако, удаляя bmp, программа использует только 17 МБ, что означает, что сотни экземпляров могут выполняться одновременно.