C# 内存泄漏与位图
C# Memory leak with Bitmap
我正在用 C# 编写一个基于图块的游戏。但是我 运行 遇到一个问题,当应用程序处于窗口模式时,我的系统内存在 +-300MB 左右波动,而在全屏模式下它会耗尽所有内存并抛出 OutOfMemoryException。
据我所知,我找不到任何地方可以忘记 .Dispose() 可能导致此问题的事情。
最接近我能查明问题的地方是我将 .Clone() 位图转换为 PictureBox.Image 的地方。这种情况每帧发生一次。我在内存中渲染了整个 "world",这是一个大约 2000x1000 像素的位图,我从中复制要显示在屏幕上的部分。
我可以附上代码,但由于代码太多,我会等到清楚问题出在那里,而不是在上面的方法中。
谢谢
编辑:我认为这是问题所在:
public Bitmap GetMap(Rectangle renderedArea)
{
if (renderedArea.Bottom > renderedMap.Height || renderedArea.Right > renderedMap.Width)
return renderedMap.Clone(new Rectangle(0,0,renderedMap.Width,renderedMap.Height),renderedMap.PixelFormat);
return renderedMap.Clone(renderedArea, renderedMap.PixelFormat);
}
public void Render(Rectangle area)
{
renderArea.Image = worldEditor.map.GetMap(area);
Graphics g = Graphics.FromImage(renderArea.Image);
PointF stringPoint = MouseInputEventHandler.CursorLocation.ToCoords(worldEditor.map.TileArray.TileSize,worldEditor.RENDER_START);
g.DrawString(string.Format("{0},{1}", (int)stringPoint.X, (int)stringPoint.Y), new Font("Arial",15,FontStyle.Bold), Brushes.Yellow, new PointF(6, 6));
g.Dispose();
}
通过查看相关问题(google 没有告诉我!)我发现将其添加到 Render() 函数中可以解决问题:
if (renderArea.Image != null)
renderArea.Image.Dispose();
不过我很想听听为什么还要处理它。
当您 Clone
时,您创建了对象的 副本。所以你的 new Bitmap
对象最终也需要 Dispose
调用它。
renderArea.Image = worldEditor.map.GetMap(area);
重新分配图像而不进行处置,因此您泄漏了旧对象。如果您将 post 中的代码添加到其中,您将清理该对象,从而解决您的问题。
一种可能更清晰的书写方式是:
Bitmap oldImage = renderArea.Image;
renderArea.Image = worldEditor.map.GetMap(area);
if (oldImage != null)
oldImage.Dispose();
我正在用 C# 编写一个基于图块的游戏。但是我 运行 遇到一个问题,当应用程序处于窗口模式时,我的系统内存在 +-300MB 左右波动,而在全屏模式下它会耗尽所有内存并抛出 OutOfMemoryException。
据我所知,我找不到任何地方可以忘记 .Dispose() 可能导致此问题的事情。
最接近我能查明问题的地方是我将 .Clone() 位图转换为 PictureBox.Image 的地方。这种情况每帧发生一次。我在内存中渲染了整个 "world",这是一个大约 2000x1000 像素的位图,我从中复制要显示在屏幕上的部分。
我可以附上代码,但由于代码太多,我会等到清楚问题出在那里,而不是在上面的方法中。
谢谢
编辑:我认为这是问题所在:
public Bitmap GetMap(Rectangle renderedArea)
{
if (renderedArea.Bottom > renderedMap.Height || renderedArea.Right > renderedMap.Width)
return renderedMap.Clone(new Rectangle(0,0,renderedMap.Width,renderedMap.Height),renderedMap.PixelFormat);
return renderedMap.Clone(renderedArea, renderedMap.PixelFormat);
}
public void Render(Rectangle area)
{
renderArea.Image = worldEditor.map.GetMap(area);
Graphics g = Graphics.FromImage(renderArea.Image);
PointF stringPoint = MouseInputEventHandler.CursorLocation.ToCoords(worldEditor.map.TileArray.TileSize,worldEditor.RENDER_START);
g.DrawString(string.Format("{0},{1}", (int)stringPoint.X, (int)stringPoint.Y), new Font("Arial",15,FontStyle.Bold), Brushes.Yellow, new PointF(6, 6));
g.Dispose();
}
通过查看相关问题(google 没有告诉我!)我发现将其添加到 Render() 函数中可以解决问题:
if (renderArea.Image != null)
renderArea.Image.Dispose();
不过我很想听听为什么还要处理它。
当您 Clone
时,您创建了对象的 副本。所以你的 new Bitmap
对象最终也需要 Dispose
调用它。
renderArea.Image = worldEditor.map.GetMap(area);
重新分配图像而不进行处置,因此您泄漏了旧对象。如果您将 post 中的代码添加到其中,您将清理该对象,从而解决您的问题。
一种可能更清晰的书写方式是:
Bitmap oldImage = renderArea.Image;
renderArea.Image = worldEditor.map.GetMap(area);
if (oldImage != null)
oldImage.Dispose();