x64位Azure计算机上的DateTimeOffset的平均大小是多少?

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中内置的语言投影隐藏了这个问题.