Home > Net >  Can storing structs in a Dictionary (vs. objects) help me?
Can storing structs in a Dictionary (vs. objects) help me?

Time:09-29

If I understand correctly, then structs are stored on the stack - unless they are referenced by an object, e.g. as a member, that is stored on the heap.

Will the Garbage Collection collect the struct, simply as part of the object - or must it handle the struct explicitly?

Background: I have a Dictionary with items that are currently classes and I'm considering changing them to structs. I'm aware that there is a price when passing the struct as parameters (because all members must basically be copied), but I'm hoping to reduce GC pressure.

CodePudding user response:

A long time ago, some wrote something about struct instances being stored on the stack, and this mis-information has stuck. What makes value types special is how they interact with assignment operations. When you assign a reference type instance to a variable (or pass it around as a method parameter), the reference is copied. When you do it with a struct instance, the value of the struct is copied.

If you have a collection of value-type objects, what happens is that the slot for storing each object is the size of the object, not the size of reference to an object.

On a 32-bit application, a List<int> will take up the same amount of space (for the ints, not for the list) as a List<SomeRandomClass>. But, it will be about half the size of a List<long>

When you create a Dictionary<int, int>, the ints get copied into the space allocated for the dictionary data. When you create a Dictionary<string, SomeRandomClass>, then the references to the objects will get copied in instead.

Value types are never garbage collected - though object instances that contain struct instances will be garbage collected. The GC doesn't care that an object to be collected has ints, DateTimes or references to SomeRandomClass or whatever within the object.

Reading @EricLippert's blog about structs/value types can be an eye-opener: https://ericlippert.com/category/value-types/

An aside:

Here's the link that points out the fallacy that structs exist on the stack: https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms229017(v=vs.100). "Value types are allocated on the stack or inline and are deallocated when they go out of scope".

That is wrong. It's frustrating that that statement is still on Microsoft's site 9 years later.

Consider this code. Every one of those member fields is a struct/value type, and everyone of them will be allocated on the managed heap for every instance of class X (and eventually garbage collected):

public class X {
    public int A;
    public long B;
    public DateTime C;
}

As to your question

"I have a Dictionary with items that are currently classes and I'm considering changing them to structs. I'm aware that there is a price when passing the struct as parameters (because all members must basically be copied), but I'm hoping to reduce GC pressure."

Don't forget that if you change things to structs, you aren't passing around references, you are passing around values. If you add something to a dictionary and then change that something, what's in the dictionary will not change. You need to think differently with structs (and, to be safe, you should make your structs immutable so you don't get into that kind of easy to mess up situation.)

And, GC Pressure is a complicated subject. Are you worried about the dictionary or its contents. If an object is long-lived (long enough to end up in Gen2 GC-land), then whether it's copied into the dictionary or it's own GC-able object shouldn't matter to much.

If you are worried about GC pressure, look around and make sure you aren't spitting out garbage objects inadvertently. Examples of doing this are concatenating strings (particularly in a loop), building up large collections of objects into a list that you didn't pre-size. Things like that.

  • Related