Memory layout problem solving for C Struct
- 2020-05-24 06:01:43
- OfStack
Question: please state the instance size and memory layout of struct below
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;
}
1 will look at the answers again to see if they differ significantly from your understanding. In fact, the memory layout of struct and class is determined by StructLayoutAttribute's construction parameters: LayoutKind enumeration, struct by the compiler to add LayoutKind.Sequential, class by the compiler to add LayoutKind.Auto. The experimental data of Sequential can be summarized as follows:
1. For struct without reference type: in the order defined, the memory layout is the same as c, c++. Such as:
Byte a;
Byte b;
Long c;
Size is a, b fills 4 bytes, c fills 8 bytes
Byte a
Long c
Byte b
The size of a is filled with 8 bytes, c with 8 bytes, b with 8 bytes
2. For fields with reference type struct: greater than 4 bytes - > Reference field - > Fields less than 4 bytes
For fields less than 4 bytes in size, memory layout is the same as rule 1 if the size is the same in defined order. One thing to note is that if the field is of type struct, it will always be last.
So the answer above is:
Struct1: c (4) > d(4) - > b(2) - > a(2)
Struct2: b (8) > d(4) - > a(1)c(1) fills in 2 bytes
Struct3: a(1)b(1) fills 2 bytes - > c(8)
Struct4: a(1) fills 7 bytes - > b(8)- > c(1) fills in 7 bytes
If you want to experiment 1 with your own hands, you'll need to use SOS.dll for debugging (there are many articles and blogs on SOS configuration and usage introduction). Take struct1 as an example:
Struct1s1 = new Struct1();
s1.a = 1;
s1.b = 15;
s1.c = "c";
s1.d = 32;
.load sos
C:\WINDOWS\ Microsoft.NET \Framework\ v2.0.50727 \ sos.dll
!clrstack -a
PDB symbol for mscorwks.dll not loaded
OS Thread Id: 0x15fc (5628)
ESP EIP
0041ee3c 03ba01aa Test_Console.Class12.Main()
LOCALS:
0x0041ee84 = 0x01b02b0c
0x0041ee74 = 0x00000020
0x0041ee68 = 0x00000000
0x0041ee50 = 0x00000000
0041f104 6ebd1b4c [GCFrame: 0041f104]
.load sos
C:\WINDOWS\ Microsoft.NET \Framework\ v2.0.50727 \ sos.dll
! name2ee *! Test_Console.Struct1 // get the method table address for Struct1
PDB symbol for mscorwks.dll not loaded
Module: 6d5d1000 (mscorlib.dll)
--------------------------------------
Module: 00192c5c (Test_Console.exe)
Token: 0x02000012
MethodTable: 00193828
EEClass: 007a45b4
Name: Test_Console.Struct1
! clrstack-a // gets the address on the stack of the struct1 instance
OS Thread Id: 0x1438 (5176)
ESP EIP
003eef0c 008f00c9 Test_Console.Class12.Main()
LOCALS:
0x003eef1c = 0x01c12b0c
003ef17c 6ebd1b4c [GCFrame: 003ef17c]
! dumpvc 00193828 0 x003eef1c / / view layout value types
Name: Test_Console.Struct1
MethodTable 00193828
EEClass: 007a45b4
Size: 20(0x14) bytes
Fields:
MT Field Offset Type VT Attr Value Name
6d84340c 400001c a System.Byte 1 instance 1 a
6d83e910 400001d 8 System.Int16 1 instance 15 b
6d8408ec 400001e 0 System.String 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'm going to show you that using dumpvc gives you an size, which is 20 bytes, which is 8 bytes more than we calculated, and I understand that because the reference type has an additional 8 bytes (syncblkindex + methodtableaddress) so size plus 8.