Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are there memory allocations when calling a func

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?

enter image description here

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);         }     } } 
like image 855
Xiaoguo Ge Avatar asked Mar 15 '18 12:03

Xiaoguo Ge


People also ask

What is the memory allocated for a function?

In allocation, function memory is divided into program memory and data memory. Program memory consists of the memory used for main and functions. Data memory consists of permanent definitions, such as global data and constants, local declarations, and dynamic data memory.

Why do we allocate memory?

Memory allocation is the process of setting aside sections of memory in a program to be used to store variables, and instances of structures and classes. There are two basic types of memory allocation: When you declare a variable or an instance of a structure or class.

When a function is called which part of the memory is used?

Locals 101: When a function is called, memory is allocated for all of its locals. In other words, when the flow of control hits the starting { for the function, all of its locals are allocated memory.

How much memory is allocated to a function in C?

One per each calling.

What is the memory allocation behavior of a function argument?

The exact memory allocation behavior is a function of the specific platform's 1 calling conventions. For example, on x86-64, space will not be allocated on the stack for the function argument; instead, it will be passed via a register ( %rcx on Windows, %rdi on *nix).

When is the memory allocated in C++?

The memory is allocated during compile time. Dynamic Memory Allocation: Memory allocation done at the time of execution (run time) is known as dynamic memory allocation. Functions calloc () and malloc () support allocating dynamic memory.

What are the reasons for allocating memory dynamically?

Reasons and Advantage of allocating memory dynamically: 1 When we do not know how much amount of memory would be needed for the program beforehand. 2 When we want data structures without any upper limit of memory space. 3 When you want to use your memory space more efficiently. ... More items...

What is the difference between static memory allocation and memory allocation?

In this memory allocation scheme, execution is slower than static memory allocation. In this memory is allocated at compile time. In this memory is allocated at run time. In this allocated memory remains from start to end of the program. In this allocated memory can be released at any time during the program.


1 Answers

You're using a method group conversion to create the Func<long, long, bool> used for the comparerFunc 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:

A new instance of the delegate type D is allocated. If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.

The section for anonymous function conversions (6.5.1) includes this:

Conversions of semantically identical anonymous functions with the same (possibly empty) set of captured outer variable instances to the same delegate types are permitted (but not required) to return the same delegate instance.

... 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.

Func<Guid[], int> func = x => Utils.Foo(x, (a, b) => Utils.ComparerFunc(a, b)); 

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 the Func<Guid[], int> from being cached - meaning that if you executed Main 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:

Func<long, long, bool> comparer = Utils.ComparerFunc; Func<Guid[], int> func = x => Utils.Foo(x, comparer); var guids = new Guid[10]; for (int i = 0; i < 1000000; i++) {     int a = func(guids); } 

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.

like image 194
Jon Skeet Avatar answered Sep 21 '22 18:09

Jon Skeet