整数数组或结构数组 - 哪个更好?

时间:2010-03-14 07:16:55

标签: c# .net memory struct rgb

在我的应用中,我将Bitmap数据存储在二维整数数组(int[,])中。要访问R,G和B值,我使用以下内容:

// read:
int i = _data[x, y];
byte B = (byte)(i >> 0);
byte G = (byte)(i >> 8);
byte R = (byte)(i >> 16);
// write:
_data[x, y] = BitConverter.ToInt32(new byte[] { B, G, R, 0 }, 0);

我使用整数数组而不是实际的System.Drawing.Bitmap,因为我的应用程序在Windows Mobile设备上运行,其中可用于创建位图的内存受到严重限制。

但是,我想知道,如果宣布这样的结构会更有意义:

public struct RGB
{
    public byte R;
    public byte G;
    public byte B;
}

...然后使用RGB数组而不是int数组。这样我就可以轻松读取和写入单独的R,G和B值,而无需进行位移和BitConverter。我依旧记得以前几天关于byte变量在32位系统上被块对齐的事情,所以byte实际占用4个字节的内存而不是1个(但也许这只是一个Visual Basic的东西)。

使用结构数组(如上面的RGB示例)会比使用整数数组更快,并且它会使用3/4内存还是内存的3倍?

4 个答案:

答案 0 :(得分:2)

为什么不在Color中使用System.Drawing结构?它更容易处理和引用。当然,它有4个字节(另一个值代表Alpha),但是你的第一个实现也是如此,如果我没记错的话,任何3个字节都会与4个字节的块对齐。看一下示例here

答案 1 :(得分:2)

单独一个字节可能会被块对齐,但结构中的多个字节可以被打包。根据Marshal.SizeOf,你的RGB结构确实只占用了三个字节的内存。 (从技术上讲,这是编组到非托管内存时的大小,CLR可以选择以不同方式进行布局;但实际上我认为这是正确的。)

但是,CLR仍然可以在RGB和其他结构之间插入填充,这种行为可能取决于处理器,CLR版本等。在x86系统上,分配3亿RGB的数组导致任务管理器报告大约900 MB承诺,而分配3亿个整数的阵列导致1200 MB承诺。所以看起来x86上的2.0 CLR可以节省25%的成本。 (我不得不承认这让我感到惊讶;就像Traveling Tech Guy一样,我希望3字节结构与4字节边界对齐。所以我可能会遗漏一些东西。)但CF可能会有所不同:你真的会只有通过在目标平台上测试才能知道。

答案 2 :(得分:2)

如果您正在使用速度,那么技术上我希望int[]版本更快,因为有一个特定的IL指令来获取来自数组的int(请参阅OpCodes.Ldelem_I4)。要做一个自定义结构,它必须获取地址(OpCodes.Ldelema),然后复制结构(OpCodes.Ldobj) - 处理这两个步骤的类型元数据。

简而言之 - int方法应该有更好的优化。但这是微优化 - 在 general 中更喜欢使代码更具可读性的版本。你可能考虑的是用int中的自定义静态隐式转换运算符编写结构到你的结构 - 然后你可以拥有int[]并仍然执行:

MyColor col = intArr[12];

(当然,它会在中间进行静态调用)

您也可以考虑使用 union ,这样您就不需要进行大量的转换:

重要我没有理智地检查这个字节顺序;只需更改R / G / B的偏移即可更改它。

class Program
{
    static void Main()
    {
        int[] i = { -1 };
        RGB rgb = i[0];
    }
}
[StructLayout( LayoutKind.Explicit)]
public struct RGB
{
    public RGB(int value) {
        this.R = this.G = this.B = 0; this.Value = value;
    }
    [FieldOffset(0)]
    public int Value;
    [FieldOffset(2)]
    public byte R;
    [FieldOffset(1)]
    public byte G;
    [FieldOffset(0)]
    public byte B;

    public static implicit operator RGB(int value) {
        return new RGB(value);
    }
    public static implicit operator int(RGB value) {
        return value.Value;
    }
}

答案 3 :(得分:1)

我认为id取决于你想要达到的目标。 它当然更适用于struct的Readabl,你可以安全地使用它与

unsafe { }

这将真正加快位图访问速度。 (如果你知道该怎么做 - 没有检查边界条件和类似的东西) 并且肯定如果你想为位图乘法,屏蔽,灰度,过滤通常的图形东西制作运算符,那么INT在速度方面是你的朋友,但不幸的是不是在可读性的情况下。 矩阵滤波器只能将所述整数(它可以这样写)而不是RGB值独立地相乘,但是Marks结构不应该是问题。 希望它有所帮助