C# 位图图像在运行时使用大量 RAM

C# Bitmap image using a lot of RAM during runtime

我今天做了一个 tilemap 生成器,我注意到当导入大小为 128x128 像素的图像并将它们拼接在一起(tilemap)成一个大位图(8192x8192 像素;64x64 tiles)时,它使用 ~250MB RAM 当输出图像到磁盘 (BinaryWriter) 只有 <400KB。我不明白为什么它在内部使用了这么多内存。

DEFAULT_TILE_SIZE = 128 DEFAULT_SIZE = 8192

这里是代码:

public static Bitmap GenerateTileMapFromDirectory(string path, int tileSize = DEFAULT_TILE_SIZE)
{
    if (!Directory.Exists(path)) throw new DirectoryNotFoundException();
    Bitmap bmp = new Bitmap(DEFAULT_SIZE, DEFAULT_SIZE);
    int x = 0, y = 0;
    foreach (string file in Directory.GetFiles(path))
    {
        string ext = Path.GetExtension(file);
        if (ext.ToLower() == ".png")
        {
            Bitmap src = (Bitmap)Bitmap.FromFile(file);
            if (src.Width != tileSize || src.Height != tileSize)
            {
                //Log that PNG was not correct size, but resize it to fit constraints...
                Console.WriteLine(Path.GetFileName(file) + " has incorrect size ... Resizing to fit");
                src = new Bitmap(src, tileSize, tileSize);
            }
            using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
            {
                g.DrawImage(src, x, y, tileSize, tileSize);
            }
            src = null;
        }
        else
        {
            Console.WriteLine(Path.GetFileName(file) + " is not a PNG ... Ignoring");
            continue;
        }
        if (x < bmp.Width) x += tileSize;
        if (x == bmp.Width)
        {
            x = 0;
            y += tileSize;
        }
        if (y == bmp.Height) break;
    }


    //For generation verification, uncomment the following two lines.
    //if (File.Exists("D:\output.png")) File.Delete("D:\output.png");
    //if (bmp!=null) bmp.Save("D:\output.png");
    return bmp;
}

您创建的 Bitmap 是 8192 x 8192,在写入磁盘之前都在内存中。位图中的每个像素需要 4 个字节(红色、绿色、蓝色、alpha)。因此,所需的内存(RAM)为 8192 x 8192 x 4 字节 = 256MB。

写入磁盘时,您可能将其保存为 PNG 格式,该格式使用无损压缩来减小文件大小。

PS - 正如 Matthew 在评论中指出的那样,您还应该用 "using" 包裹 src 位图,或者妥善处理它。

我还会创建一次图形,而不是每个图块,因为您会一次又一次地使用它。