Bitmap.Clone()的奇怪行为

时间:2013-01-24 16:31:03

标签: c# bitmap clone bitmapdata

 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!!

这怎么可能?

2 个答案:

答案 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代码来克隆位图,你会看到已经过去的时间。