I have the following program which construct a local Func from two static methods. But strangely, when I profile the program, it allocated close to a million Func objects. Why invoking Func object is also creating Func instances?
public static class Utils
{
public static bool ComparerFunc(long thisTicks, long thatTicks)
{
return thisTicks < thatTicks;
}
public static int Foo(Guid[] guids, Func<long, long, bool> comparerFunc)
{
bool a = comparerFunc(1, 2);
return 0;
}
}
class Program
{
static void Main(string[] args)
{
Func<Guid[], int> func = x => Utils.Foo(x, Utils.ComparerFunc);
var guids = new Guid[10];
for (int i = 0; i < 1000000; i++)
{
int a = func(guids);
}
}
}
You're using a method group conversion to create the
Func<long, long, bool>
used for thecomparerFunc
parameter. Unfortunately, the C# 5 specification currently requires that to create a new delegate instance each time it's run. From the C# 5 specification section 6.6, describing the run-time evaluation of a method group conversion:The section for anonymous function conversions (6.5.1) includes this:
... but there's nothing similar for method group conversions.
That means this code is permitted to be optimized to use a single delegate instance for each of the delegates involved - and Roslyn does.
Another option would be to allocate the
Func<long, long, bool>
once and store it in a local variable. That local variable would need to be captured by the lambda expression, which prevents theFunc<Guid[], int>
from being cached - meaning that if you executedMain
many times, you'd create two new delegates on each call, whereas the earlier solution would cache as far as is reasonable. The code is simpler though:All of this makes me sad, and in the latest edition of the ECMA C# standard, the compiler will be permitted to cache the result of method group conversions. I don't know when/whether it will do so though.