#c# #garbage-collection
#c# #сборка мусора
Вопрос:
У меня есть этот фрагмент кода («ruta1» и «ruta2» — это строки, содержащие путь к разным изображениям):
Bitmap pic;
Bitmap b = new Bitmap(SomeWidth, SomeHeight);
g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
b.Save(ruta2, ImageFormat.Jpeg);
g.Dispose();
b.Dispose();
b = new Bitmap(OtherWidth, OtherHeight);
pic = new Bitmap(ruta2);
g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
g.DrawImage(pic, 0, 0, pic.Height, pic.Width);
pic.Dispose();
b.Save(ruta2, ImageFormat.Jpeg);
g.Dispose();
b.Dispose();
pic = new Bitmap(ruta1);
b = new Bitmap(AnotherWidth, AnotherHeight);
g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
int k = 1;
// I just draw the "pic" in a pattern on "b"
for (h = 0; h <= b.Height; h = pic.Height)
for (w = 0; w <= b.Width; w = pic.Width)
g.DrawImage(pic, w, h, k * pic.Width, k * pic.Height);
pic.Dispose();
GC.Collect(); // If I comment this line, I get a "generic GDI Error" Exception
b.Save(ruta1, ImageFormat.Jpeg);
g.Dispose();
b.Dispose();
Не имеет значения, установил ли я pic = null после удаления, если я не вызываю сборщик мусора, я получаю исключение «Общая ошибка GDI «. Только когда я вызываю сборщик мусора, моя программа всегда работает нормально.
Кто-нибудь может объяснить такое поведение? Зависит ли это от .Версия Net framework? Я использую Visual C # Express 2008, с .Net framework 3.5
Ответ №1:
Во-первых, было бы неплохо, если бы вы использовали ключевое слово « using
» для расширения области использования ваших одноразовых объектов (таких как Bitmap
и Graphics
), вместо того, чтобы вызывать Dispose()
вручную для каждого. Использование « using
» лучше по многим причинам, таким как очистка содержимого при возникновении исключения, но это также значительно улучшает читаемость кода.
Во-вторых, кисти GDI также являются IDisposable
объектами, поэтому вам не следует создавать их и забывать. Сделайте это вместо:
using (var brush = new SolidBrush(Color.White))
{
g.FillRectangle(brush, 0, 0, width, height)
}
… или, что еще лучше, создайте свои кисти в начале вашего приложения и сохраняйте их до конца (но не забудьте также избавиться от них). IIRC, создание / удаление кистей сильно влияет на производительность, если выполняется часто.
В-третьих, я полагаю, что ваша ошибка находится во 2-м разделе:
- Вы открываете изображение «ruta2»
- Вы создаете новый образ
- Вы рисуете содержимое «ruta2» внутри этого нового изображения
- Вы сохраняете эту новую вещь поверх файла «ruta2», но исходное изображение с шага 1 все еще загружено и, вероятно, имеет какой-то дескриптор в файле «ruta2», поэтому вам нужно избавиться от него перед перезаписью файла.
Если вы реорганизуете этот 2-й раздел подобным образом, он должен работать:
using (var b = new Bitmap(OtherWidth, OtherHeight))
using (var g = Graphics.FromImage(b))
{
using (var brush = new SolidBrush(Color.Red))
{
g.FillRectangle(brush, 0, 0, b.Width, b.Height);
}
using (var pic = new Bitmap(ruta2))
{
g.DrawImage(pic, 0, 0, pic.Height, pic.Width);
}
b.Save(ruta2, ImageFormat.Jpeg);
}
Комментарии:
1. Я забыл использовать слово «using» при использовании кода, который я использую для использования: D : D : D