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 位图,或者妥善处理它。
我还会创建一次图形,而不是每个图块,因为您会一次又一次地使用它。
我今天做了一个 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 位图,或者妥善处理它。
我还会创建一次图形,而不是每个图块,因为您会一次又一次地使用它。