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

这怎么可能?

4

2 回答 2

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);
}

您会看到应用程序的内存消耗缓慢而稳定地上升。

于 2013-01-24T16:58:55.993 回答
1

您的第一个代码片段运行得如此之快的原因很可能是因为优化器看到它copy从未使用过并且只是将其删除。如果您将内部循环更改为:

var copy = source.Clone() as Bitmap;
var copy2 = copy;

...它可能会诱使编译器实际生成 IL 代码以克隆位图,并且您会看到经过的时间增加。

于 2013-01-24T16:37:17.380 回答