When Structs Create Garbage
C# has a huge advantage over languages like Java and AS3: the struct
. It allows us to create a value type with multiple members and avoid creating garbage every time we create one with new
. At least that’s the simple version of the story. In reality, it’s really easy to accidentally create garbage with struct
. Today’s article shows how to use struct
so that you don’t create any garbage and reveals some of the traps so you won’t fall into them.
Let’s start with the sunny side of struct
. Creating one and storing it as a local variable doesn’t create any garbage:
struct Struct { } void Foo() { var x = new Struct(); // no garbage created }
You can also pass the local variable as a parameter to another function that takes that type of struct
without creating any garbage:
void Foo() { var x = new Struct(); // no garbage created Take(x); // no garbage created } void Take(Struct x) { }
None of this changes if the struct
implements an interface
:
interface Interface { } struct Struct : Interface { }
But we start to run into problems when we mix these two. Passing the struct
as a parameter to a function that takes the interface
type suddenly creates garbage:
void Foo() { var x = new Struct(); // no garbage created Take(x); // creates garbage! } void Take(Interface x) { }
Worse still, it creates garbage every time you call the function:
void Foo() { var x = new Struct(); // no garbage created Take(x); // creates garbage! Take(x); // creates more garbage! Take(x); // creates even more garbage! } void Take(Interface x) { }
The same is true when the function takes a plain object
instead of the struct
or interface
type:
void Foo() { var x = new Struct(); // no garbage created Take(x); // creates garbage! } void Take(object x) { }
Update: This is incorrect because Nullable is a struct
It’s even worse when the function takes a nullable (?
) parameter because an instance of Nullable
is created behind the scenes:
void Foo() { var x = new Struct(); // no garbage created Take(x); // creates even more garbage! } void Take(Struct? x) { }
When the function has a type parameter (i.e. uses generics), no garbage is created by calling the function:
void Foo() { var x = new Struct(); // no garbage created Take(x); // no garbage created } void Take<T>(T x) { }
In all, that’s three ways to create garbage with struct
and two ways to not create garbage. Just by the numbers, it’s easier to accidentally create garbage with struct
than it is to avoid creating garbage. This means we need to keep our guard up when using struct
and not just assume that it magically removes all garbage creation and GC problems. Make sure to pay special attention to the functions you call when using struct
or you just might inadvertently create a bunch of garbage!
Do you know of any more ways to accidentally create garbage in C#? Let me know in the comments!
#1 by Stan on December 28th, 2018 ·
Nullable
is a struct in c# – no garbage is created.#2 by jackson on December 29th, 2018 ·
You’re absolutely correct. I’ve updated the article to strike that section from the article.