none
Object Layout Question RRS feed

  • Question

  • I have a fairly detailed question on .NET object layout. Consider the following object that uses FieldOffsets for explicit layout:

    public sealed class MyObject {
    [FieldOffset(0)] private ulong the_only_data_that_is_used_for_hashcode_equals_tostring_operations;
    [FieldOffset(8)] private ulong the_only_data_that_is_used_for_abc_operation;
    [FieldOffset(16)] private ulong the_only_data_that_is_used_for_xyz_operation;
    }

    My question is: is this an optimal layout? I purposefully put the hashcode/equals/tostring data at fieldOffset(0), because that's closer to the method table pointer, and both are used during the virtual method calls for GetHashCode()/Equals()/ToString(). So the probability of inducing an unnecessary cache miss is slightly lower than if it were later on in the object. Also, since abc_operation and xyz_operation do NOT use virtual calls, does it matter at what field offset they are located? My guess is not, because internally the CLR shoud be doing a direct function call and only using pObject->the_only_data_that_is_used_for_abc_operation and completely skipping the entire object header/method table pointer/first fields. Are my assumptions correct, and therefore it would be slightly less optimal to have the hashcode/equals/tostring data at a later point in the object layout? And having hashcode/equals/tostring data as the first data will not slow down abc_operation and xyz_operation?

    Monday, March 21, 2016 8:00 PM

Answers

  • "My question is: is this an optimal layout?"

    Yes.

    But in practice I'd be surprised if it makes a measurable difference. It would be best to check if whatever scenario you have that requires such a micro optimization is actually affected by this.

    "I'm suspecting this is correct based on the Mono source code, but I'd still like a confirmation this is true in .NET and that there's not some other .NET behavior that I'm missing."

    It doesn't matter in this case but note that in .NET the synchronization stuff come before the vtable, at a negative offset (-4 or -8 depending on bitness).

    Monday, March 21, 2016 9:34 PM
    Moderator

All replies

  • I'm suspecting this is correct based on the Mono source code, but I'd still like a confirmation this is true in .NET and that there's not some other .NET behavior that I'm missing.

    https://github.com/mono/mono/blob/master/docs/object-layout

    typedef struct {
    MonoVTable *vtable;
    MonoThreadsSync synchronisation;

    /* object specific data goes here */
    } MonoObject;

    Monday, March 21, 2016 8:20 PM
  • "My question is: is this an optimal layout?"

    Yes.

    But in practice I'd be surprised if it makes a measurable difference. It would be best to check if whatever scenario you have that requires such a micro optimization is actually affected by this.

    "I'm suspecting this is correct based on the Mono source code, but I'd still like a confirmation this is true in .NET and that there's not some other .NET behavior that I'm missing."

    It doesn't matter in this case but note that in .NET the synchronization stuff come before the vtable, at a negative offset (-4 or -8 depending on bitness).

    Monday, March 21, 2016 9:34 PM
    Moderator
  • Thank you for your answer!

    "But in practice I'd be surprised if it makes a measurable difference. It would be best to check if whatever scenario you have that requires such a micro optimization is actually affected by this."

    I agreed. This is the first and probably the last time I'll ever use FieldOffset within a managed object - the usage is incredibly specific. From my testing, (1) putting the vtable-related data at the beginning indeed made no difference (i don't use vcalls in high-perf scenarios), but (2) organizing fields based on common operations increasingly helped as object size increased

    Tuesday, March 22, 2016 2:55 PM