Does inlining reduce allocations?

Started by
6 comments, last by Shaarigan 4 years, 2 months ago

Not a real problem, I'm just looking to satisfy curiosity…

Vector GetVector()
{
	return new Vector(0, 5);
}
void Update()
{
	DoSomething(GetVector() * 2);
}
Vector GetVector()
{
	Vector vec = new Vector(0, 5);
	return vec;
}
void Update()
{
	Vector vec = GetVector();
	Vector twiceVector = vec * 2;
	DoSomething(twiceVector);
}

In the first example, value is returned, operator function called, and passed in, all inline. Whereas in the second example, each step stores the value as a local.

Would both examples compile the same? Or are there additional allocations (however small) in the second?

Edit: Sorry don't know why this posted to AI. I mustn't have specified a category.

Advertisement

In most cases the compiler will be able to optimise both examples down to `DoSomething(Vector(0, 10))` and there may not be any allocations at all if it's clear that the vector then gets thrown away.

Is there a chance that certain types of code layout could change the way the compiler optimises the code? Yes. Is it likely, if the code is simple and there are no hidden side-effects? No.

It also strongly depends on whether Vector is declared as “class” or “struct”. A struct will most likely be allocated on the stack anyways, so it shouldn't make a difference. (A vector of two floats/ints is a strong candidate for being a struct).

Juliean said:

It also strongly depends on whether Vector is declared as “class” or “struct”. A struct will most likely be allocated on the stack anyways, so it shouldn't make a difference. (A vector of two floats/ints is a strong candidate for being a struct).

Hold it there, I was always under the impression the that only discernible difference was the default specifier (private/public)?

**edit* C#, never mind my ignorance

The compiler is supposed to inline small functions anyways. The biggest difference in allocations is stack vs. heap, structs are plain data, even if they declare functions while classes are always heap memory.

A little tricky is if you assign stack (value) to heap types (reference). Object is always a reference type, same for instances of interfaces. Assigning a struct to an object causes the compiler to box the type (heap memory is allocated and the value is copied to). Same for lets say assigning the return value of GetEnumerator to IEnumerator, here also happens boxing.

Btw. you can also “force” C# to use pointers to managed types. This is the only way to pass value types by reference without boxing

The compiler is supposed to inline small functions anyways.

Unfortunately, that might not be the case depending on the toolset you work with. Specifically Unity, the most popular use-case of C#, is notoriously bad at inlining. Even the most recent documentation still mentions that Unitys compiler doesn't inline much (we have internal discussions whether this is still the case, or if the documentation is simply outdated - would be interesting to hear if somebody knows more).

There was no mention of Unity, yes Unity and especially Mono is e.g. was quite stupid in the past. Roslyn is considered to be smarter and Microsoft improved it a lot so my statement is correct for plain C#. Unity now also supports .Net 4.5 and up and also uses Roslyn, additonally there is the equivalent to C++'s force inline compiler hint as decorator attribute

This topic is closed to new replies.

Advertisement