Suppose I have some small data type - for example a simple point implementation. I can either implement this type as a reference type (class), or as a value type (struct).
public class PointClass
{
public readonly int X;
public readonly int Y;
}
public readonly struct PointStruct
{
public readonly int X;
public readonly int Y;
}
// Not shown, constructors, equality/hashcode members, etc
Now, suppose I were to create a collection of these types. I might use a basic array, or more likely, a standard System.Collections.Generic.List, which itself uses a backing array.
In the case of the reference type, creating new instances would allocate them on the heap, and so these data would need to be garbage collected at some point. The array would contain reference data pointing to the instances of the points wherever they are on the heap.
Alternatively, if I were to use the value type implementation, would the array contain "the raw bytes" to house the int fields? That is, a new instance would be allocated on the stack, its data copied by value into the array, and so only the array itself needs to be garbage collected.
My thinking is that this second approach (using the value type) would be better for storing lots of these small data types. Of course, I am aware of the overheads involved with "large" structs - this example is specifically about a small type.
Is this statement about the value type accurate? Or will there still be garbage collection for the value types? Is my understanding correct, or am I greviously missing the point about value types?
In the case of the reference type, creating new instances would allocate them on the heap, and so these data would need to be garbage collected at some point.
Yes, but at a cost of storing both the pointer and the data. The benefit is only if the objects are actually collected. If they are never collected then there is no gain.
Note also that lists resize to accommodate, but never shrink unless you tell them to. Therefore the space taken up for references is normally lost until the whole list is collected. (The same is true for value-types obviously, I'm just pointing out the gain isn't as much as you might think.)
if I were to use the value type implementation, would the array contain "the raw bytes" to house the int fields? That is, a new instance would be allocated on the stack, its data copied by value into the array, and so only the array itself needs to be garbage collected.
Yes that's exactly what a value-type is.
...this second approach (using the value type) would be better for storing lots of these small data types. Of course, I am aware of the overheads involved with "large" structs - this example is specifically about a small type.
Yes, but now you have a copy problem every time you want to move around this data. As soon as your data is larger than double the pointer size (which it may well be due in many cases due to padding), you are always copying more than a pointer. "Large" structs don't have to be very large to cause a problem.
To be honest, you shouldn't really be thinking about any of this unless you are using truly massive numbers of these. Otherwise, code to what makes the most sense and don't worry about the performance impact, which will be negligible in most cases.