There have been a lot of discussion around this and everyone tend to agree that you should always call Delegate.EndInvoke to prevent a memory leak (even Jon Skeet said it!).
I always followed this guideline without questioning, but recently I implemented my own AsyncResult class and saw that the only resource that could leak is the AsyncWaitHandle.
(In fact it doesn't really leak because the native resource used by the WaitHandle is encapsulated in a SafeHandle which has a Finalizer, it will add pressure on the finalize queue of the garbage collector though. Even so, a good implementation of AsyncResult will only initialize the AsyncWaitHandle on demand...)
The best way to know if there is a leak is just to try it:
Action a = delegate { };
while (true)
a.BeginInvoke(null, null);
I ran this for a while and the memory stay between 9-20 MB.
Let's compare with when Delegate.EndInvoke is called:
Action a = delegate { };
while (true)
a.BeginInvoke(ar => a.EndInvoke(ar), null);
With this test, the memory play between 9-30 MG, weird eh? (Probably because it takes a bit longer to execute when there is an AsyncCallback, so there will be more queued delegate in the ThreadPool)
What do you think... "Myth busted"?
P.S. ThreadPool.QueueUserWorkItem is a hundred more efficient than Delegate.BeginInvoke, its better to use it for fire & forget calls.