Why is 16 byte the recommended size for struct in C#?
Solution 1:
You're misquoting the book (at least the 2nd edition). Jeffrey Richter states value types can be more than 16 bytes if:
You don't intend to pass them to other methods or copy them to and from a collection class.
Additionally Eric Gunnerson adds (regarding the 16 byte limit)
Use this guideline as a trigger to do more investigation.
It is simply not true that a struct "has to be less than 16 bytes in size". It all depends on usage.
If you are creating the struct and also consuming it and are worried about performance then use a profiler comparing a struct vs class to see which works best for you.
Solution 2:
Only you know how your structs are being used in your program. But if nothing else, you can always test it for yourself. For instance, if it's frequently passed to other functions, the following may illuminate you:
class MainClass
{
static void Main()
{
Struct64 s1 = new Struct64();
Class64 c1 = new Class64();
DoStuff(s1);
DoStuff(c1);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
s1 = DoStuff(s1);
}
sw.Stop();
Console.WriteLine("Struct {0}", sw.ElapsedTicks);
sw.Reset();
sw.Start();
for (int i = 0; i < 10000; i++)
{
c1 = DoStuff(c1);
}
sw.Stop();
Console.WriteLine("Class {0}", sw.ElapsedTicks);
sw.Reset();
Console.ReadLine();
}
}
with:
public class Class64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
public struct Struct64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
Try this sort of thing with representative structs/classes, and see what results you get. (On my machine, above test, the class seems ~3 times faster)
Solution 3:
The JIT compiler produces special-case code to copy structures which are smaller than a certain thresholds, and a somewhat-slower general-purpose construct for larger ones. I would conjecture that when that advice was written, the threshold was 16 bytes, but in today's 32-bit framework it seems to be 24 bytes; it may be larger for 64-bit code.
That having been said, the cost of creating any size class object is substantially greater than the cost of copying a struct which holds the same data. If code creates a class object with 32 bytes worth of fields and then passes or otherwise copies a reference to that object 1,000 times, the time savings from copying 1,000 object references instead of having to copy 1,000 32-byte structures would likely outweigh the cost of creating the class object. If, however, the object instance would be abandoned after the reference has been copied only twice, the cost of creating the object would probably exceed by a large margin the cost of copying a 32-byte structure twice.
Note also that it's possible in many cases to avoid passing around structures by value or otherwise redundantly copying them, if one endeavors to do so. Passing any size of structure as a ref
parameter to a method, for example, only requires passing a single-machine-word (4 or 8 bytes) address. Because .net lacks any sort of const ref
concept, only writable fields or variables may be passed that way, and the collections built into .net--other than System.Array
--provide no means to access members by ref
. If one is willing to use arrays or custom collections, however, even huge (100 bytes or more) structures can be processed very efficiently. In many cases, the performance advantage of using a structure rather than an immutable class may grow with the size of the encapsulated data.