GeistHaus
log in · sign up

A new stackalloc operator for reference types with CoreCLR and Roslyn | xoofx

xoofx.com

Home Blog Projects About A new stackalloc operator for reference types with CoreCLR and Roslyn October 8, 2015 C#, Roslyn, CoreCLR, .Net edit Source code is now available on github Udpdated 9 Oct 2015: Added a section about the this and transient safe problem Udpdated 10 Oct 2015: Added a section about escape analysis In the sequel of my previous post adding...

2 pages link to this URL
Value Types vs Reference Types

tl;dr structs have better data locality. Value types add much less pressure for the GC than reference types. But big value types are expensive to copy and you can accidentally box them which is bad. Introduction The .NET framework implements Reference Types and Value Types. C# allows us to define custom value types by using struct and enum keywords. class, delegate and interface are for reference types. Primitive types, like byte, char, short, int and long are value types, but developers can’t define custom primitive types. In Java primitive types are also value types, but Java does not expose a possibility to define custom value types for developers ;) Value Types and Reference Types are very different in terms of performance characteristics. In my next blog posts, I am going to describe ref returns and locals, ValueTask<T> and Span<T>. But I need to clarify this matter first, so the readers can understand the benefits. Note: To keep my comparison simple I am going to use ValueTuple<int, int> and Tuple<int, int> as the examples. Memory Layout Every instance of a reference type has extra two fields that are used internally by CLR. ObjectHeader is a bitmask, which is used by CLR to store some additional information. For example: if you take a lock on a given object instance, this information is stored in ObjectHeader. MethodTable is a pointer to the Method Table, which is a set of metadata about given type. If you call a virtual method, then CLR jumps to the Method Table and obtains the address of the actual implementation and performs the actual call. Both hidden fields size is equal to the size of a pointer. So for 32 bit architecture, we have 8 bytes overhead and for 64 bit 16 bytes. Value Types don’t have any additional overhead members. What you see is what you get. This is why they are more limited in terms of features. You cannot derive from struct, lock it or write finalizer for it. RAM is very cheap. So, what’s all the fuss about?