Click here to Skip to main content
15,867,568 members
Please Sign up or sign in to vote.
4.83/5 (6 votes)
See more:
I know what delegates are and how, when and why to use them. But I have never really understood how they work as far as memory allocation is concerned.

It is similar to function pointer. So we can say that it holds reference to a method. Now, value types are stored in stack and references are stored in a heap. So, if I create a delegate object, it should be stored in a heap. But where exactly is it pointing to? I assume memory allocation in case of objects and methods should be different. Is there anyone around here to help me understanding the background memory games related to delegates?
Posted
Comments
wizardzz 17-Jun-11 13:02pm    
If it wasn't you posting this, I'd fear people would tag it HW! I'm not mocking you, and I wish I could help.
Sergey Alexandrovich Kryukov 17-Jun-11 14:08pm    
Please see my answer -- quite interesting (see my comment below).
--SA
dan!sh 17-Jun-11 15:36pm    
I am really surprised. I have never had formal education on computers/programming but I am almost sure that this is not taught.
Sergey Alexandrovich Kryukov 20-Jun-11 1:36am    
No, this is not taught. By the way, I also don't have formal education, I'm a physicist.
--SA
Richard MacCutchan 17-Jun-11 13:23pm    
I don't actually know the answer but I wonder if looking at the MSIL code would help? As I understand it a delegate is merely a dynamic table that contains pointers to the actual code to be executed as each is called. If you know COM I think it's a bit like the vtable.

First, let's see the difference between delegate and delegate instance. A delegate (type) is a pure method signature; and a delegate instance is something different.

First surprise: delegate instance type is completely different from the related delegate type.

delegate void Action(); //delegate type

Action myAction = () => { System.Console.WriteLine("action"); }
//now Action.GetType() is NOT typeof(Action)


If you get Action.GetType and look at it at throw reflection, you will see, that this is a… class with many members. Most importantly, it has a method GetInvocationList.

Delegate instance internally is not a pointer! Is is a collection of "pointers". But not pointers, its is a collection of other delegates with invocation lists each of one item. What is that item?

It is not a pointer either. Functionally, it's "double pointer": one points to code of a handler, another is a reference to class or structure instance passed to the handler during the call in the form of hidden parameter "this". This reference is null for static handlers. Both static and non-static (instance) handlers are allowed.

So, any delegate instance is always multi-cast.
The process of adding handlers to invocation list is very interesting. Delegate instances loose their referential identity as a result of this operation, pretty much like strings, because these types are immutable.

I describe this is my article Dynamic Method Dispatcher[^], please see the section "4.1 On the Nature of Delegate Instance".

Now, the following references to heap are involve: a references to the delegate instance itself, as an instance of class and the reference to each "this" of each handler in the invocation list. An pointer to the code does not matter and does not need garbage collection. Garbage Collector (GC) deals with those references exactly as with any other ones.

GC looks for all references which can not be accessed by any currently running code in the Application Domain. All inaccessible instances are scheduled for destruction, and the memory will be reclaimed, but some time later. (That's way any code relying on the order of destructor calls is incorrect and the destructors are rarely have to be written.) This is not trivial. If the some instances reference each other in a loop, they will be destroyed anyway.

If some access by references exists, it delays garbage collection. Having an instance of some class in some delegate's invocation list is not an exclusion. To make garbage collection possible, a delegate instance itself should be lost, or a handler should be removed from the invocation list.

By the way, failure to take it into account can make yet another source of memory leaks in a .NET application. Yes, memory leaks are possible, but they can happen due to design issues, not due to a random coding bug.

—SA
 
Share this answer
 
v8
Comments
Vivek Krishnamurthy 17-Jun-11 14:36pm    
Nice! 5 :)
Atul Khanduri 15-Oct-13 4:11am    
Great one.... 5...:)
Sergey Alexandrovich Kryukov 17-Jun-11 14:37pm    
Thank you, Vivek.
So many surprises and misconceptions about this matter. Not trivial.
--SA
Sergey Alexandrovich Kryukov 15-Oct-13 11:00am    
Thank you, Atul.
—SA
Parwej Ahamad 17-Jun-11 15:13pm    
Good conceptual explanation! Thanks. 5 :)
One of the best descriptions of delegates and how memory allocation works with it, is detailed in this[^] article. It's worth reading it a few times to get a better understanding of what the underlying impact of delegates really is.
 
Share this answer
 
Comments
dan!sh 18-Jun-11 5:40am    
Thanks Pete.
DaveyM69 18-Jun-11 6:32am    
Great link Pete, very interesting.
Sergey Alexandrovich Kryukov 20-Jun-11 2:12am    
Agree, there are couple of more interesting points, especially lexical closure. However, this is a simple consequence of how delegate work plus possibility of the anonymous methods. This topic is slightly outside the question of delegates, but certainly good to know and relevant to memory allocation.
My 5.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900