当我在XNA游戏中制作屏幕截图时,每个texture.SaveAsPng
消耗一些内存并且它似乎不会返回游戏。所以最终我的内存耗尽了。我尝试将纹理数据保存到FileStream
和MemoryStream
,希望我可以将其保存为Bitmap
,但结果是相同的。有没有办法强行释放这个内存或一些解决方法,让我获取图像数据并以其他方式保存,而不会遇到内存不足异常?
sw = GraphicsDevice.Viewport.Width;
sh = GraphicsDevice.Viewport.Height;
int[] backBuffer = new int[sw * sh];
GraphicsDevice.GetBackBufferData(backBuffer);
using(Texture2D texture = new Texture2D(GraphicsDevice, sw, sh, false,
GraphicsDevice.PresentationParameters.BackBufferFormat))
{
texture.SetData(backBuffer);
using(var fs = new FileStream("screenshot.png", FileMode.Create))
texture.SaveAsPng(fs, sw, sh); // ← this line causes memory leak
}
答案 0 :(得分:2)
您可以直接从纹理字节创建位图,并绕过内部方法以检查SaveAsPng
是否泄漏或其他内容。
尝试这种扩展方法(不幸的是我无法测试(没有xna在工作)但是应该工作。)
public static class TextureExtensions
{
public static void TextureToPng(this Texture2D texture, int width, int height, ImageFormat imageFormat, string filename)
{
using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
byte blue;
IntPtr safePtr;
BitmapData bitmapData;
Rectangle rect = new Rectangle(0, 0, width, height);
byte[] textureData = new byte[4 * width * height];
texture.GetData<byte>(textureData);
for (int i = 0; i < textureData.Length; i += 4)
{
blue = textureData[i];
textureData[i] = textureData[i + 2];
textureData[i + 2] = blue;
}
bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
safePtr = bitmapData.Scan0;
Marshal.Copy(textureData, 0, safePtr, textureData.Length);
bitmap.UnlockBits(bitmapData);
bitmap.Save(filename, imageFormat);
}
}
}
它有点粗糙,但你可以清理它(如果它甚至可以工作)。
最后但并非最不重要(如果所有其他尝试都失败了)您可以自己致电GarbageCollection
,但不推荐这是非常糟糕的做法。
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
上述代码应该是最后的代码。
祝你好运。