我想在C#中的16字节边界上对齐一个浮点数组。
我所知道的一种技术是固定数组: http://meekmaak.blogspot.ca/2010/06/c-memory-aligned-array-wrapper-for-fast.html
我不喜欢钉住记忆的想法。我担心它会如何影响垃圾收集的性能。
还有其他技巧吗?我正在考虑创建一个16字节的结构,分配它的数组,然后将数组转换为浮点数组。
[StructLayout(LayoutKind.Explicit)]
public struct Float4 {
[FieldOffset(0)] public float X;
[FieldOffset(4)] public float Y;
[FieldOffset(8)] public float Z;
[FieldOffset(12)] public float W;
}
我不确定下一步会做什么(不同类型阵列之间的铸件)以及最佳方法是什么?
答案 0 :(得分:1)
根据您正在做的事情,使用具有明确布局的结构可能是有意义的,其中包含至少一个long
或double
与您的float
变量重叠(我认为验证者会允许,但我不确定)或使用一些手动管理的内存。包含超过22,000个浮点数的数组将分配给大对象堆;我认为包含IIRC 2,000的阵列也将同样对齐,但我不知道该处理是否适用于64位系统,或者它是否适用于包含双精度的结构阵列。如果你的阵列不够大,那么#34;属于"在大对象堆上,您可能需要分配一个大型数组并手动将其部分分配给各种消费者。
在某些版本的.NET上,可能已经可以分配一个带有三个额外元素的数组,并使用一个DLL,它通过引用接受float
,报告其地址的2-3位,以及移位浮点数在数组中以确保正确对齐(例如,如果您想要256个值的数组,分配259,如果DLL报告arr[0]
位于地址0x12345ABC,请使用数组插槽#1-#256)。这种方法的困难在于GC可能会不时地随意移动物体,因此可能必须周期性地在阵列中向上或向下移动元素以便校正它们的对齐。此外,我不知道是否有可能迫使编组人员做一个真实的"传递参考"而不是代替"传值 - 导致" [后者传递临时缓冲区的地址,而不是数组元素]。根据我的理解,某些版本的.NET很容易进行替换。
我个人有点疑惑.NET为什么没有做出大的努力来将大多数对象与缓存行对齐。盲目地将对象填充到下一个16字节的倍数将最多浪费额外的60%的空间(最坏的情况是20字节的对象填充到32);为12字节,20字节和24字节对象添加一些特殊情况逻辑可以将最坏情况的开销减少到14%。由于大多数对象用法之前都是对其类型引用的访问,因此在同一缓存行中具有前几个字段的字段数据似乎是性能获胜。