tags:

views:

73

answers:

3

Hi folks:

I'm studying struct; some book advises creating struct if it has an instance size less than 16 bytes.

Why?

Thanks for any reply.

A: 

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.

Bart van Heukelom
A 64 bit pointer is still cheaper than 128 bits of struct. This answer doesn't really make much sense.
slugster
+2  A: 

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. Above 64 bytes there is a jump, where the time suddenly quadruples when the size doubles, this is probably where the fallback hits in for this version.

Guffa
you bring up a lucent point of view
Ricky
where does your point come from?
Ricky
@Ricky: I have done some testing over the years. I added a current test result above.
Guffa
@Guffa: Do you have tests that measure the amount of time needed to copy a reference to a class?
rstevens
@Guffa: u are Guru!
Ricky
+1  A: 

A struct is a value type which means it's content lays on the stack and is copied each time it is passed from one variable to another one or as an argument into a function. An instance of a reference type (class keyword in C#) lays on the (garbage collected) heap and only a reference to it is passed around.

Allocating an object on the heap is relatively expensive compared to "allocating" space on the stack, also passing around a reference needs some work to do. So if the payload is small a struct is much faster than a class. But this may change if the payload grows.

But keep in mind that there is a big difference in passing a copy or passing a reference: If passing a reference, modifying the class behind that reference is visible to all places the reference is used. Modifying a copy of a value type is only visible on the place where that copy is used.

It depends on what you want if one or the other is better.

rstevens
Hmm not sure I agree with a lot of this. Structs are not necessarily allocated on the stack e.g. when the struct is a member variable of a class. Also I'd dispute that allocating in the c# heap is 'relatively expensive'. As it's a GC heap, the alloc typically just increments a pointer in the process heap
zebrabox
@zebrabox: You're right for instance member structs. But allocating on GC heap is not "simply increasing a pointer in the process heap". There are locks around this to make it thread-safe and initialization of the references and so on.
rstevens