Reputation: 9081
I'd like to use the Marshall.SizeOf() method in my application
class Class1
{
static void Main()
{
Console.WriteLine("Number of bytes needed by a PointB object: {0}",
Marshal.SizeOf(typeof(PointB)));
Console.WriteLine("Number of bytes needed by a PointA object: {0}",
Marshal.SizeOf(typeof(PointA)));
Console.ReadKey();
}
public struct PointA
{
public int x;
public string posorneg;
public bool isvalid;
}
public struct PointB
{
public bool isvalid;
public int x;
public string posorneg;
}
}
I got as result :
Number of bytes needed by a PointB object: 16
Number of bytes needed by a PointA object: 24
I don't understand this result and I need to know :
Upvotes: 4
Views: 252
Reputation: 941327
You are running this code in 64-bit mode, object references take 8 bytes. The default value of StructLayout.Pack is 8, matching the default setting for most C compilers. It ensures that members of a struct are aligned to an address that's a multiple of the member size. An important rule to make code fast and to keep updates to variables atomic. It avoids the processor having to use multiple memory bus cycles to access the variable value.
Annotating where every member is stored in the memory allocated for the struct:
public struct PointA
{
public int x; // Offset 0, 4 bytes
// Offset 4, 4 bytes of padding
public string posorneg; // Offset 8, 8 bytes
public bool isvalid; // Offset 16, 4 bytes
// Offset 20, 4 bytes of padding
} // Total: 24 bytes
public struct PointB
{
public bool isvalid; // Offset 0, 4 bytes
public int x; // Offset 4, 4 bytes
public string posorneg; // Offset 8, 8 bytes
} // Total: 16 bytes
The first 4 bytes of padding needed to be inserted to keep the string reference member aligned to 8. The last 4 bytes of padding where needed to ensure that the string is still aligned when you store the struct in an array.
No padding at all required in PointB, everything lined up correctly by accident. You can easily see the effect of the Pack attribute, apply [StructLayout(LayoutKind.Sequential, Pack = 4)]
to the structs and you'll see they now both take 16 bytes. It is of course not actually possible in practice to reorder fields or tinker with the packing, you need to match the layout of the struct that the native code used.
Very notable is that the CLR performs this kind of layout optimization automatically. On a class or a struct with the [StructLayout(LayoutKind.Auto)]
applied, it reorders fields to get the best layout. One of the niceties of managed code, making it competitive with native code. Do keep in mind that what you see from the Marshal class only applies after the class or struct is marshaled. The internal layout is undiscoverable, the reason that the CLR can play these optimization tricks.
Upvotes: 4