Reputation: 3899
I have a struct:
public struct MyStruct
{
public readonly string Str1;
public readonly string Str2;
}
According to the Internet, you really should only use structs if their size is 16 bytes or less. If more, performance issues can happen. From various searches, a string stores 2 bytes per character. This means that if you have a string in a struct, it could only have 8 characters at most, assuming it's the only string in your struct. In my example, that'd be split among both fields I have.
Elsewhere, however, I've read that only the string reference is put in the struct, not the string itself.
My question is: Does the 16 byte recommendation/limitation of C# structs mean that I basically can't use strings in them. I like taking advantage of structs sometimes (especially the cannot-be-null parts of it), so I want to know if there's still a way to use them while following the recommendations.
EDIT: Poor choice of words on my part. Indeed it's not a limitation of the language, but rather a recommendation based on performance to not exceed 16 bytes in one's structs. I think I'm falling victim to premature optimization here: Perhaps I should only worry about this limitation if I see actual performance problems in my application, rather than fretting over small numbers of bytes.
Upvotes: 6
Views: 2688
Reputation: 81159
Advice regarding the 16-byte threshold should be considered out of date. The .NET Runtime optimizes operations on structures below a certain size (which used to be 16 bytes, but has since increased to I think 24); the cost per byte increases when structures exceed that size, but that doesn't mean one should use a class for everything larger than that.
The cost of creating a new structure is proportional to its size. The cost of creating a new class object is proportional to its size plus some significant additional overhead. The cost of copying an existing structure is proportional to its size, with a penalty for structs over a certain size. The cost of copying a reference to an immutable class object is fixed and small.
Creating a structure of any size and copying it once or twice will always be cheaper than creating a class object of the same size and copying the reference likewise. If the structure or class reference would get copied millions of times, even a 12-byte class might outperform a 12 byte structure. For values in between, the break-even size for class vs. structure will depend upon the number of times a struct or class reference would get copied, but unless a type is really big or would be copied many thousands of times, the extra cost to copy structures will still be cheaper than the extra cost to create class objects.
With regard to the fact that a structure contains strings, one should regard a reference to an immutable-type object as having a cost of 4 or 8 bytes on a 32-bit or 64-bit system. Since a string
field does not "hold" a string but merely identifies one, a struct with two string
fields would thus take 8 or 16 bytes, regardless of the lengths of the strings identified thereby.
Upvotes: 12
Reputation: 10708
As mentioned, this particular case will only store the reference to string
- and references are always sized according to architecture. This means references are 4 bytes on x86 and 8 bytes on x64 platforms. Don't forget your program will usually be made to run on either x86 or x64.
You can check whether a particular type will pass by reference or by reference (ie take up full size or just pointer sizes) by seeing whether it is deifned as a class
(reference) or a struct
(value). If you're using Visual Studio or Xamarin, just select a type name and hit 'f12' to see the metadata for that type - which will include class
or struct
delcaration.
Upvotes: 1
Reputation: 36333
String
is a reference type, so in this case, you are only holding 2 references to your two string
s however long they are. The 2 references, are 4 bytes each on a 32-bit system, and 8 byte each on a 64-bit system. They contain the memory address of your strings.
The guideline of this 16 byte struct limitation
is probably because when you are passing a struct (vs. a class), the values get copied. If the struct is large, then a lot of memory copying will be done, which will negatively impact the performance.
Upvotes: 5