var source = new Bitmap(2000,2000);
var sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
//var copy = new Bitmap(source);
var copy = source.Clone() as Bitmap;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
使用我的系统,代码在10毫秒内运行,并且Ram使用率保持不变。 使用此计时器和Ram使用结果,不能有Bitmapdata的副本。
但是当我这样做的时候。
var copy2 = source.Clone() as Bitmap;
for (int x = 0; x < copy2.Width; x++)
{
for (int y = 0; y < copy2.Height; y++)
{
copy2.SetPixel(x, y, Color.Red);
}
}
// copy2 is Red
// source is NOT!!
这怎么可能?
答案 0 :(得分:2)
您的source
被复制了10,000次。对Clone()
的调用无法进行优化,因为编译器不知道方法调用可能产生的副作用。
当然,你的克隆没有保留,所以垃圾收集器可能会选择很快摆脱它们(可能在循环仍在运行时)。
您也可以保留克隆。试试这个:
var source = new Bitmap(2000, 2000);
var li = new List<Bitmap>();
var sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
li.Add((Bitmap)source.Clone());
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.WriteLine(li.Count);
li[4321].SetPixel(1234, 123, Color.Blue);
Console.WriteLine(li[1234].GetPixel(1234, 123)); // checks if a pixel of another clone also changed to blue
编辑:从某种意义上说,克隆似乎是“懒惰”。上面的代码运行速度非常快,并没有使用太多内存。即使source
是一个非常复杂的位图,似乎也会发生同样的事情,所以这不仅仅是source
位图可以被“压缩”的时候发生的事情。
如果在构建上面的列表li
之后,运行以下代码:
var randomNumberGenerator = new Random();
for (int x = 0; x < 10000; ++x)
{
for (int i = 0; i < 2000; ++i)
for (int j = 0; j < 2000; ++j)
li[x].SetPixel(i, j, System.Drawing.Color.FromArgb(randomNumberGenerator.Next()));
Console.WriteLine(x);
}
你会看到应用程序的内存消耗缓慢而稳定地上升。
答案 1 :(得分:1)
您的第一个代码段运行速度非常快的原因非常可能,因为优化程序会发现copy
从未使用过,只是将其删除。如果您将内循环更改为:
var copy = source.Clone() as Bitmap;
var copy2 = copy;
...它可能会欺骗编译器实际生成IL代码来克隆位图,你会看到已经过去的时间。