Question: Please tell me the following struct instance size and memory layout
struct Struct1
{
public byte a;
public short b;
public string c;
public int d;
}
struct Struct2
{
public byte a;
public long b;
public byte c;
public string d;
}
struct Struct3
{
byte a;
byte b;
long c;
}
struct Struct4
{
byte a;
long b;
byte c;
}
Let’s look at the answers later to see if there is a big difference from your understanding? In fact, the memory layout of struct and class is determined by the StructLayoutAttribute's constructor parameters: LayoutKind enumeration, struct is added by the compiler, and class is added by the compiler. Sequential can be summarized as follows through experimental data:
1. For structs without reference types: arrange in the order of definition, the memory layout and C++ rules are the same. for example:
Byte a;
Byte b;
Long c;
The size is a, b is filled with 4 bytes and c is filled with 8 bytes
Byte a
Long c
Byte b
The size of a is filled with 8 bytes, c is filled with 8 bytes, b is filled with 8 bytes
2. For structs with reference type: fields greater than 4 bytes -> Reference fields -> Fields less than 4 bytes
For fields smaller than 4 bytes, the memory layout and rule 1 are the same if the size is the same, and if the size is the same, the order in which the memory layout is the same. However, there is one thing to note here that if the field is of the same struct type, then this field is always at the end.
So the answer above is:
Struct1:c(4) -> d(4) -> b(2) ->a(2)
Struct2: b(8) -> d(4) -> a(1)c(1)Fill 2 bytes
Struct3: a(1)b(1)Fill 2 bytes -> c(8)
Struct4: a(1) fills 7 bytes -> b(8)->c(1) fills 7 bytes
If you want to experiment with it yourself, you need to debug it (there are many articles on SOS configuration and introduction to use) Take struct1 as an example:
Struct1s1 = new Struct1();
= 1;
= 15;
= "c";
= 32;
.load sos
Extension C:\WINDOWS\\Framework\v2.0.50727\ loaded
!clrstack -a
PDB symbol for not loaded
OS Thread Id: 0x15fc (5628)
ESP EIP
0041ee3c 03ba01aa Test_Console.()
LOCALS:
0x0041ee84 = 0x01b02b0c
0x0041ee74 = 0x00000020
0x0041ee68 = 0x00000000
0x0041ee50 = 0x00000000
0041f104 6ebd1b4c [GCFrame: 0041f104]
.load sos
Extension C:\WINDOWS\\Framework\v2.0.50727\ loaded
!name2ee *!Test_Console.Struct1 //Get the method table address of Struct1
PDB symbol for not loaded
Module: 6d5d1000 ()
--------------------------------------
Module: 00192c5c (Test_Console.exe)
Token: 0x02000012
MethodTable: 00193828
EEClass: 007a45b4
Name: Test_Console.Struct1
!clrstack -a //Get the stack address of the struct1 instance
OS Thread Id: 0x1438 (5176)
ESP EIP
003eef0c 008f00c9 Test_Console.()
LOCALS:
0x003eef1c = 0x01c12b0c
003ef17c 6ebd1b4c [GCFrame: 003ef17c]
!dumpvc 00193828 0x003eef1c //View the layout of the value type
Name: Test_Console.Struct1
MethodTable 00193828
EEClass: 007a45b4
Size: 20(0x14) bytes
Fields:
MT Field Offset Type VT Attr Value Name
6d84340c 400001c a 1 instance 1 a
6d83e910 400001d 8 System.Int16 1 instance 15 b
6d8408ec 400001e 0 0 instance 01c12b0c c
6d842b38 400001f 4 System.Int32 1 instance 32 d
In the memory window, you can see that the memory layout is:
0x003EEF1C 01c12b0c 00000020 0001000f
Here I want to explain that after using dumpvc, a size will be given. Here is 20 bytes, which is 8 bytes more than the result we calculated. My understanding is that because the reference type has an additional 8 bytes (syncblkindex + methodtableaddress), the size here is also added to 8.