简体   繁体   English

.NET自定义结构类型的内存开销是多少?

[英]What is the memory overhead of a .NET custom struct type?

There is a fixed overhead associated with a .NET object as more fully outlined in this SO question: What is the memory overhead of a .NET Object being 12 or 24 bytes depending on whether you are in a 32 bit or 64 bit process. 有一个与.NET对象相关的固定开销,在这个SO问题中有更全面的概述: .NET对象的内存开销是12或24字节,具体取决于你是在32位还是64位进程。

That said, basic value types like int, double, boolean , etc incur no overhead because they are Value Types . 也就是说,像int, double, boolean等基本值类型不会产生任何开销,因为它们是值类型

Where does that leave custom struct types that you put together in your application? 在您的应用程序中放置自定义struct类型的位置在哪里? On the one hand, they are value types like int, double, boolean above [so should not incur overhead] but on the other hand they derive indirectly from System.Object and so should (technically) incur overhead. 一方面,它们是值类型,如上面的int, double, boolean [所以不应该产生开销]但另一方面它们间接地从System.Object派生,因此(技术上)应该产生开销。

Where does that leave custom struct types that you put together in your application? 在您的应用程序中放置自定义结构类型的位置在哪里?

They are no different than primitive types. 它们与原始类型没有什么不同。 They carry no additional overhead other than the fields they have. 除了他们拥有的领域之外,它们不会带来额外的开销。 The fact that they derive from object doesn't mean they incur the overhead that reference types carry, which is the method table pointer and sync root block. 它们从object派生的事实并不意味着它们会产生引用类型携带的开销,即方法表指针和同步根块。

You can test this out using Marshal.SizeOf : 你可以使用Marshal.SizeOf来测试它:

void Main()
{
    var f = new Foo();
    Console.WriteLine(Marshal.SizeOf(f));
}

public struct Foo
{
    public int X { get; set; }
    public int Y { get; set; }
}

This will print 8 in a 32bit mode, which is exactly two integer values (4 bytes each). 这将以32位模式打印8,这正好是两个整数值(每个4个字节)。

Note Marshal.SizeOf will output the size of the unmanaged object. 注意Marshal.SizeOf将输出非托管对象的大小。 The CLR is still free to re-order fields or pack them together. CLR仍然可以自由地重新排序字段或将它们打包在一起。

The size of a struct is determined by the sum of the sizes of its fields plus the padding between the fields that get them aligned properly, plus padding at the end of the struct that ensures that they are still aligned properly when the struct is stored in an array. 结构的大小由其字段大小的总和加上正确对齐的字段之间的填充,加上结构末尾的填充,确保在结构存储时它们仍然正确对齐数组。

So, for one, a struct is not entirely unlikely to contain a field of a reference type. 因此,对于一个,结构并不完全不可能包含引用类型的字段。 Like a string. 像一个字符串。 In which case the struct is going to be larger since references are pointers under the hood, taking 8 bytes instead of 4. 在这种情况下,结构将变得更大,因为引用是引擎盖下的指针,占用8个字节而不是4个字节。

The padding is the much sneakier detail. 衬垫是更加狡猾的细节。 In 32-bit mode, variables cannot count on an alignment better than 4. An issue with double and long , 8 byte types that can easily get mis-aligned. 在32位模式下,变量不能指向优于4的对齐。 doublelong ,8字节类型的问题很容易被错误对齐。 Notably affecting perf of a 32-bit program, if a double is misaligned across an L1 cache boundary line then a read or write can be 3x as slow. 特别是影响32位程序的性能,如果双重在L1高速缓存边界线上未对齐,则读取或写入速度可能是3倍。 Also the core reason that these types are not atomic in the C# memory model. 这也是C#内存模型中这些类型不是原子的核心原因。 Not an issue in 64-bit mode, the CLR then must and does provide an alignment guarantee of 8. 在64位模式下不是问题,然后CLR必须并确实提供8的对齐保证。

Nevertheless, the CLR does attempt to give such struct members proper alignment in 32-bit mode, even though the struct itself is not guaranteed to be aligned. 然而,CLR确实试图在32位模式下给这样的结构成员正确对齐,即使结构本身不能保证对齐。 Otherwise a side-effect of structs having an implicit [StructLayout(LayoutKind.Sequential, Pack=8)] attribute. 否则,结构的副作用具有隐式[StructLayout(LayoutKind.Sequential, Pack=8)]属性。 An oddity in the CLR source code, the C++ statement that does this has no comment. CLR源代码中的一个奇怪的是,执行此操作的C ++语句没有注释。 I suspect it was a quicky fix for less than stellar unmanaged interop perf, keeping structs blittable is pretty important to speed. 我怀疑它是一个快速修复不到恒星非托管互操作性能 ,保持结构blittable对速度非常重要。

You'll however not always get this, the CLR gives up if the struct contains a member that is itself a struct that does not have sequential layout. 然而,如果结构包含一个本身就是没有顺序布局的结构的成员,那么CLR就会放弃。 Notably this happens for DateTime and DateTimeOffset , the programmers who wrote them applied the [StructLayout(LayoutKind.Auto)] attribute on them for very mysterious reasons. 值得注意的是,这发生在DateTimeDateTimeOffset ,编写它们的程序员在其上应用[StructLayout(LayoutKind.Auto)]属性是出于非常神秘的原因。 In the case of DateTimeOffset likely to be a copy/paste bug. 在DateTimeOffset的情况下可能是复制/粘贴错误。 Layout of your struct will now be unpredictable, it becomes LayoutKind.Auto as well and the CLR re-arranges fields to minimize the struct size. 结构的布局现在将是不可预测的,它也变为LayoutKind.Auto,CLR重新排列字段以最小化结构大小。 This can cause extra padding in x64 mode. 可能会导致x64模式下的额外填充。

These are obscure implementation details that you should never fret about. 这些是不应该担心的模糊实现细节。

You may have some overhead with fields' alignments : 字段的对齐可能会有一些开销:

https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute(v=vs.100).aspx https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute(v=vs.100).aspx

Eg 例如

  public struct Test {
    public Byte A;
    public long B;
  }

will be of size 16 bytes on 64-bit process and 12 bytes on 32-bit process correspondingly (when we could expect 9 bytes only); 将大小在64位处理16个字节和12个字节在32位过程相应地(当我们可以预期只有9个字节);

Zero. 零。

Unless there's gaps due to alignment, in which case it's the cost of those gaps. 除非由于对齐而存在间隙,否则这就是这些差距的成本。

But otherwise the structure is just the same as if the fields were separate variables laid out on the stack. 但是否则结构就像字段是在堆栈上布局的单独变量一样。

Box it though, and you're dealing with it via object which has the same overheads as any other reference type. 虽然它是盒子,你通过object处理它,它具有与任何其他引用类型相同的开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM