正确处理位图对象
Properly disposing of Bitmap object
我正在使用 C# Winforms 面板绘制图像:
private void DrawPanel_Paint(object sender, PaintEventArgs e)
{
DrawOnPanel(e.Graphics);
}
被调用的方法从我的资源 (myImage) 获取现有图像,将其提供给另一个调整图像大小的方法,returns 调整大小的图像以便绘制。
public static void DrawOnPanel(Graphics g)
{
var _resizedImage = ResizeImage(Resources.myImage);
g.DrawImage(_resizedImage, destX, destY);
// ... several other images resized & manipulated then drawn
}
图片调整功能为:
public Bitmap ResizeImage(Bitmap image)
{
int scale = 3;
var destImage= new Bitmap(image.Width * scale, image.Height * scale);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.SmoothingMode = SmoothingMode.HighSpeed;
graphics.PixelOffsetMode = PixelOffsetMode.None;
using var wrapMode = new ImageAttributes();
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
return destImage;
}
程序在其循环中不断调用 DrawPanel.Invalidate()。
每次调用 DrawPanel.Invalidate() 时,我都会检测到内存泄漏。内存消耗一直在稳步上升,直到 GC 处理它为止。虽然这不是破坏游戏的问题,但我仍然想知道我应该在哪里以及如何处理上面代码中的对象。
我尝试在上面的 DrawOnPanel
方法中使用 using var _resizedImage = ResizeImage(Resources.myImage);
但程序 returns 出现错误 System.ArgumentException: 'Parameter is not valid.'
。如果我删除 using
没有错误。
每次调用 ResizeImage 时,您都会创建一个新的位图。一旦您知道不再需要该位图,就应立即将其处置。在图形上绘制后,您似乎不需要调整大小的图像。因此,我建议进行以下更改:
public static void DrawOnPanel(Graphics g)
{
using (Image_resizedImage = ResizeImage(Resources.myImage))
{
g.DrawImage(_resizedImage, destX, destY);
}
// resizedImage is Disposed
// ... several other images resized & manipulated then drawn
}
改进空间
您当前的设计将在每次调用 DrawOnPanel
时创建一个新的调整大小的位图。在我看来,大多数时候 Resources.myImage 调整大小后调整大小的位图将是相同的。你为什么不记住它,直到影响调整大小的位图的参数发生变化?
如果我查看代码,您似乎总是从原始图像创建相同大小的图像。因此,您甚至可以将所有调整大小的图像放入一个字典中以便快速查找:
// get all Image resources that you will resize and put them in a Dictionary
// Key original Bitmap, Value: resized Bitmap
private Dictionary<Bitmap, BitMap> images = this.FetchImages()
.ToDictionary(
// Parameter keySelector: key is original image
image => image,
// Parameter valueSelector: value is the resized image
imgage => ResizeImage(original));
显示调整大小后的图像现在会快得多:只需查找。
public static void DrawOnPanel(Graphics g)
{
var _resizedImage = this.Images[Resources.myImage];
g.DrawImage(_resizedImage, destX, destY);
// ... several other images resized & manipulated then drawn
}
不要忘记在关闭表单时或最迟在处理表单时处理位图:
protected override void Dispose(bool disposing)
{
if (disposing)
{
foreach (var resizedImage in images.Values)
resizedImage.Dispose();
}
}
我正在使用 C# Winforms 面板绘制图像:
private void DrawPanel_Paint(object sender, PaintEventArgs e)
{
DrawOnPanel(e.Graphics);
}
被调用的方法从我的资源 (myImage) 获取现有图像,将其提供给另一个调整图像大小的方法,returns 调整大小的图像以便绘制。
public static void DrawOnPanel(Graphics g)
{
var _resizedImage = ResizeImage(Resources.myImage);
g.DrawImage(_resizedImage, destX, destY);
// ... several other images resized & manipulated then drawn
}
图片调整功能为:
public Bitmap ResizeImage(Bitmap image)
{
int scale = 3;
var destImage= new Bitmap(image.Width * scale, image.Height * scale);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.SmoothingMode = SmoothingMode.HighSpeed;
graphics.PixelOffsetMode = PixelOffsetMode.None;
using var wrapMode = new ImageAttributes();
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
return destImage;
}
程序在其循环中不断调用 DrawPanel.Invalidate()。
每次调用 DrawPanel.Invalidate() 时,我都会检测到内存泄漏。内存消耗一直在稳步上升,直到 GC 处理它为止。虽然这不是破坏游戏的问题,但我仍然想知道我应该在哪里以及如何处理上面代码中的对象。
我尝试在上面的 DrawOnPanel
方法中使用 using var _resizedImage = ResizeImage(Resources.myImage);
但程序 returns 出现错误 System.ArgumentException: 'Parameter is not valid.'
。如果我删除 using
没有错误。
每次调用 ResizeImage 时,您都会创建一个新的位图。一旦您知道不再需要该位图,就应立即将其处置。在图形上绘制后,您似乎不需要调整大小的图像。因此,我建议进行以下更改:
public static void DrawOnPanel(Graphics g)
{
using (Image_resizedImage = ResizeImage(Resources.myImage))
{
g.DrawImage(_resizedImage, destX, destY);
}
// resizedImage is Disposed
// ... several other images resized & manipulated then drawn
}
改进空间
您当前的设计将在每次调用 DrawOnPanel
时创建一个新的调整大小的位图。在我看来,大多数时候 Resources.myImage 调整大小后调整大小的位图将是相同的。你为什么不记住它,直到影响调整大小的位图的参数发生变化?
如果我查看代码,您似乎总是从原始图像创建相同大小的图像。因此,您甚至可以将所有调整大小的图像放入一个字典中以便快速查找:
// get all Image resources that you will resize and put them in a Dictionary
// Key original Bitmap, Value: resized Bitmap
private Dictionary<Bitmap, BitMap> images = this.FetchImages()
.ToDictionary(
// Parameter keySelector: key is original image
image => image,
// Parameter valueSelector: value is the resized image
imgage => ResizeImage(original));
显示调整大小后的图像现在会快得多:只需查找。
public static void DrawOnPanel(Graphics g)
{
var _resizedImage = this.Images[Resources.myImage];
g.DrawImage(_resizedImage, destX, destY);
// ... several other images resized & manipulated then drawn
}
不要忘记在关闭表单时或最迟在处理表单时处理位图:
protected override void Dispose(bool disposing)
{
if (disposing)
{
foreach (var resizedImage in images.Values)
resizedImage.Dispose();
}
}