.NET 对象大小的填充?

10

msdn表示:

sizeof运算符只能在不安全的代码块中使用。虽然您可以使用Marshal.SizeOf方法,但此方法返回的值并不总是与sizeof返回的值相同。

以及

Marshal.SizeOf在类型进行了编组后返回大小,而sizeof返回已由公共语言运行时分配的大小,包括任何填充。

我曾经在书中读到过:c# via clr (第522页)

这样说:

问题:

1)这里提到的填充是否为:

enter image description here

请注意,以下是需要翻译的内容:

这是否与书中提到的相同

2)如果我有一个Person对象类型-如何知道它在内存中的真实大小

编辑-为什么我需要它?

请注意this

他们有一个阅读记录的样本:

 using (var accessor = mmf.CreateViewAccessor(offset, length))
            {

                int colorSize = Marshal.SizeOf(typeof(MyColor)); //<--------HERE
                MyColor color;


                for (long i = 0; i < length; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(10);
                    accessor.Write(i, ref color);
                }
            }
        }

如果MARSHAL.sizeOF报告的大小与sizeOF不同,那么应该选择哪个?它必须准确!!
根据这个示例,他们没有考虑填充,但他们应该...(或者不应该...)

由于我正在使用内存映射文件,并且有一个包含许多人员记录的文件,因此我需要知道偏移长度。 - Royi Namir
1个回答

5
这可能看起来有点不真诚 - 但从内存映射文件的角度来看,您感兴趣的大小与内存中该对象的大小不同。它们可能被称为内存映射文件,但在 .Net 中,这并不一定意味着与本机代码相同。 (尽管底层实现仍然相同 - 逻辑内存的一部分被映射到文件的一部分,因此名称仍然正确) sizeof返回包括任何填充字节在内的物理内存中对象的正确大小。因此,如果需要以本机内存术语了解对象的确切大小,请使用该值(但是这不适用于内存映射文件,我马上会解释)。
正如文档所述,Marshal.SizeOf从 .Net 的角度报告对象的大小,不包括两个隐藏的数据项; 它们仅由运行时使用。
您复制的示例使用Marshal.SizeOf,因为填充值仅涉及物理对象在内存中的情况。当对象被序列化时,仅序列化逻辑.Net数据。当再次加载对象时,基于运行时状态重新分配这两个填充的值。例如,类型指针可能不同。将它们序列化是毫无意义的。这就像将一个本机指针(而不是偏移量)序列化到磁盘上 - 它指向的数据极不可能在下一次处于相同的位置。
因此 - 如果您想知道100个Color对象数组在物理内存中使用了多少 - 请使用sizeof;如果您想知道相同数据的内存映射文件有多大,请使用Marshal.SizeOf

更新了我的回答。将你所知道和喜欢的.Net对象视为逻辑数据,实际内存为物理内存。通常情况下,您永远不需要物理内存,即使使用内存映射文件-因为在.Net中,您处理的是映射到逻辑数据而不是物理内存的文件。是的,底层实现确实使用内存映射文件;但是.Net然后使用它来种植其他对象。 - Andras Zoltan
从书和MSDN中看到的填充问题是一样的吗? - Royi Namir
我相信是这样的 - 我不知道 .Net 运行时还有其他的填充方式。唯一可能的事情可能是单词边界对齐,但那涉及到对象在内存中位置的起始点,所以我怀疑它是否适用。 - Andras Zoltan
因为我是直接访问内存,所以我确实需要大小和填充,因此我使用了marshal.sizeOf? - Royi Namir
但是你并不需要担心这个问题 - .Net会在运行时添加填充值,当它根据从内存映射文件中读取的数据创建对象时。你正在读取的内存只是.Net数据的逻辑视图... - Andras Zoltan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接