14

I'm studying .NET structs - some books advise creating structs if they have an instance size less than 16 bytes.

Why is that?

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Ricky
  • 34,377
  • 39
  • 91
  • 131
  • duplicate of http://stackoverflow.com/questions/1082311/why-should-a-net-struct-be-less-than-16-bytes – Mike Two Mar 13 '10 at 10:06
  • Also a dupe of http://stackoverflow.com/questions/2407691/c-struct-design-why-16-byte-is-recommended-size/2407869#2407869 – slugster Mar 13 '10 at 10:23

2 Answers2

37

It's because 16 bytes is the threshold where the compiler starts copying structs as block of memory instead of using one or two simple move instructions.

The compiler optimises the copying of structures when they are small. A struct that is for example eight bytes can be copied as a single 64 bit value. A struct that is 16 bytes can be copies as one or two singular values (depending on the processor architecture). When the structure is larger than 16 bytes, the compiler doesn't try to optimise the move any more, and the fallback is to call a method that copies a block of memory.

(Note: the threshold of 16 bytes may differ depending on the version of compiler, it seems as it actually tries to optimise beyond that point in newer versions, but the optimised code will still be a lot of move instructions, compared to copying a reference to an object which still is a single move operation.)

Edit:
Here is the result of a test that I did on my 64 bit system copying structs half a billion times:

struct 4    : 272 ms.
struct 8    : 235 ms.
struct 16   : 317 ms.
struct 32   : 625 ms.
struct 64   : 1280 ms.
struct 128  : 4659 ms.
struct 256  : 8020 ms.

As you see, below 16 bytes the time is not linear, although 16 bytes is four times as much as 4 bytes, it doesn't take four times longer. Above 16 bytes the time is linear, so doubling the size double the time. That's where it would start using multiple moves. Above 64 bytes there is a jump, where the time suddenly quadruples when the size doubles. That's where the fallback would start to be used.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Do you have tests that measure the amount of time needed to copy a reference to a class? – mmmmmmmm Mar 13 '10 at 13:39
  • 1
    Last I checked, x86 upped the threshold to 20 bytes, and x64 bumped it to 24. A table with power-of-two values wouldn't notice, but a structure needs to hold e.g. a GUID plus a reference--even though it's larger than 16 bytes, would copy quickly on both x86 and x64. – supercat Oct 19 '14 at 20:52
  • 64 bytes happens to be the cache line size of your PC's CPU. The jump above that size might be related to it. – Timo Apr 13 '17 at 09:07
  • "A struct that is for example eight bytes can be copied as a single 64 bit value" - Isn't that the same as saying "A struct that is for example 64 bits can be copied as a single 64 bit value" ? – David Klempfner Nov 25 '17 at 08:04
  • @Guffa I agree with your statement, that being said, I don't get it, cause if you're checking the ratio ms / byte copied, you can see that the actual gap occurs when copying a struct of 128 bytes. Resp. 68; 29.375; 19.8125; 19.53125; 20; 36.3984375; 31.328125 – Natalie Perret May 22 '20 at 20:28
  • @Guffa Could you please re-run your test and post the updated results? – Tobias Knauss Feb 08 '23 at 19:28
2

It's not exactly 16 bytes, but because structs are passed by value (copied whenever you give them to a method, assign them, etc.) they must not be too large. If they are, passing stuff by reference is cheaper.

4 years later: I answered this knowing very little about .NET (still don't know much about it). Guffa's answer is obviously more correct when dealing with "more or less than 16 bytes?", since at that size a bit of copying shouldn't matter much. My answer may be something to keep in mind when building huge structs.

Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • A 64 bit pointer is still cheaper than 128 bits of struct. This answer doesn't really make much sense. – slugster Mar 13 '10 at 10:21
  • 2
    "A 64 bit pointer is still cheaper than 128 bits of struct". Why do you say that? Acquiring a pointer usually means heap allocation and garbage collection which is expensive on .NET. Writing a pointer implies incurring a write barrier which is also expensive on .NET. – J D Dec 31 '11 at 19:04
  • @slugster: An 8-byte reference could be copied more cheaply than a 16-byte structure, but for a reference to be useful it must identify an object on the heap. Creating a heap object with 16 bytes of data and copying a reference to it a million times might be cheaper than copying a 16-byte structure a million times, but creating a 16-byte object, copying the reference twice, and abandoning it will be a lot more expensive than copying a 16-byte structure twice (or probably, for that matter, even twenty times). – supercat Oct 19 '14 at 20:56