CSharp对象的内存结构

内存结构

  • 对象类型指针(MethodTable方法表包含类型及其方法)可获得类型定义
  • 同步块索引占4字节,64位系统额外需要4字节对齐
  • 托管内存中对齐:32位系统4字节对齐,64位需要8字节对齐
  • 托管内存中智能排列字段使对象占用尽量少的内存
  • 托管对象无法使用代码获取其大小
  • StructLayout是用于封送非托管对象时使用,不影响托管内存中的排布方式

托管内存中的占用情况

1
2
3
4
5
6
7
8
class()
{
int number; //4 bytes
char c; //2 bytes
double d; //8 bytes
float f; //4 bytes
bool b; //1 byte
}
1
2
3
4
5
6
7
8
9
10
11
---------------------------------------------------
| Method Table Pointer | 8 bytes
|-------------------------------------------------|
| Synchronization Block Index | 8 bytes
|-------------------------------------------------|
| double | 8 bytes
|-------------------------------------------------|
| int | float | 8 bytes
|-------------------------------------------------|
| bool| char | | 8 bytes
---------------------------------------------------

非托管内存排布

  • 此对齐方式只是针对于在输出为非托管对象时的字段排列方式,在托管内存中不生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// 摘要:
// Controls the layout of an object when exported to unmanaged code.
public enum LayoutKind
{
//
// 摘要:
// The members of the object are laid out sequentially, in the order in which they
// appear when exported to unmanaged memory. The members are laid out according
// to the packing specified in System.Runtime.InteropServices.StructLayoutAttribute.Pack,
// and can be noncontiguous.
Sequential = 0,
//
// 摘要:
// The precise position of each member of an object in unmanaged memory is explicitly
// controlled, subject to the setting of the System.Runtime.InteropServices.StructLayoutAttribute.Pack
// field. Each member must use the System.Runtime.InteropServices.FieldOffsetAttribute
// to indicate the position of that field within the type.
Explicit = 2,
//
// 摘要:
// The runtime automatically chooses an appropriate layout for the members of an
// object in unmanaged memory. Objects defined with this enumeration member cannot
// be exposed outside of managed code. Attempting to do so generates an exception.
Auto = 3
}

Sqquential 顺序布局

  • CLR对struct的Layout的处理方法与C/C++中默认的处理方式相同,即按照结构中占用空间最大的成员进行对齐(Align)
1
2
3
4
5
6
7
8
9
10
[StructLayout(LayoutKind.Sequential)]
class Sample()
{
int number; //4 bytes
char c; //2 bytes
double d; //8 bytes
float f; //4 bytes
bool b; //1 byte
}
//sizeof(Sample) = 40个字节

Explicit 精准布局

  • CLR不对结构体进行任何内存对齐(Align)
  • 需要用FieldOffset()设置每个成员的位置
1
2
3
4
5
6
7
8
9
10
[StructLayout(LayoutKind.Explicit)]
class Sample()
{
[FieldOffset(0)]
int number1;
[FieldOffset(0)]//公用体
int number2;
[FieldOffset(4)]
int number2;
}

Auto 自动布局

  • CLR会对结构体中的字段顺序进行调整,使实例占有尽可能少的内存,并进行4byte的内存对齐(Align)

StructLayout特性三种附加字段

Charset

  • CharSet定义在结构中的字符串成员在结构被传给DLL时的排列方式。可以是Unicode、Ansi或Auto。
  • 默认为Auto,在WIN NT/2000/XP中表示字符串按照Unicode字符串进行排列,在WIN 95/98/Me中则表示按照ANSI字符串进行排列。

Pack

  • Pack定义了结构的封装大小。可以是1、2、4、8、16、32、64、128或特殊值0。特殊值0表示当前操作平台默认的压缩大小。