Mar*_*ers 3 c# memory sizeof marshalling datetimeoffset
我一直在尝试DateTimeOffset在代码中获取结构的大小,以便我可以计算父对象的大小.问题是sizeof操作员和Marshal.SizeOf功能都不能用于此目的.
sizeof将无法工作,因为我必须使用unsafe标志进行编译,而这个功能还不足以证明这一点.Marshal.SizeOf引发异常:
类型'System.DateTimeOffset'不能作为非托管结构封送; 不能计算有意义的大小或偏移量.
我已经放弃尝试计算像这样的结构的大小,因为每一行攻击/博客文章都会出现一个或另一个错误.
有人可以告诉我64位Azure Web服务器上DateTimeOffset的平均大小是多少?
Han*_*ant 15
接受的答案是不正确的,它忽略了对齐.结构的大小不仅仅是其成员的总和.可能需要字段之间的额外空间以及结构的末尾,以帮助处理器有效地读取字段并实现.NET内存模型提供的原子性保证.
对DateTimeOffset来说,这是一个额外的错综复杂,编写DateTimeOffset结构的Microsoft程序员通过复制/粘贴DateTime结构来开始编码,这是一个很大的错误.哪个历史错误对DateTimeOffset很重要,因为它有两个字段而不是一个字段.它使用LayoutKind.Auto而不是Sequential.在参考源中轻松可见
这使得CLR的余地能够在运行的任何模式下将字段排列为最佳.在32位模式下,它不会像往常那样将Int64与8个字节对齐,而是与4个字节对齐.这样可以减少字段之间的填充,大小为12个字节.
同样,在64位模式下,它喜欢将字段对齐到8.这会在字段之间产生更多填充.
看到这个的唯一好方法是使用调试器.运行这段代码:
static void Main(string[] args) {
var arr = new DateTimeOffset[] {
new DateTimeOffset(0x123456789abcdef0, TimeSpan.FromMinutes(60)),
new DateTimeOffset(0x123456789abcdef0, TimeSpan.FromMinutes(60)),
};
System.Diagnostics.Debugger.Break();
}
Run Code Online (Sandbox Code Playgroud)
当断点命中时,使用Debug> Windows> Memory> Memory1并&arr[0]在Address框中键入以查看数组内容.你会看到类似的东西:
0x00000115DC4FBA30 3c 00 00 00 00 00 00 00 f0 76 f8 38 70 56 34 12 <.......ðvø8pV4.
0x00000115DC4FBA40 3c 00 00 00 00 00 00 00 f0 76 f8 38 70 56 34 12 <.......ðvø8pV4.
0x00000115DC4FBA50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Run Code Online (Sandbox Code Playgroud)
您可以轻松查看偏移字段(60 = 0x003c)和DateTime字段.我调整了窗口的大小,使2个元素显而易见,在你的机器上看起来不那么干净:)但是只计算字节,直到它们重复,DateTimeOffset 在64位模式下占用16个字节.
32位和64位模式之间的大小不同的事实一般应该让您大吃一惊.这个bug本来就不需要修复,DateTimeOffset没有合理的互操作故事,它永远不会匹配等效的非托管类型.它是WinRT(又名UWP)中指定的互操作类型,但CLR中内置的语言投影隐藏了这个问题.