Об этом много дискутировали, и каждый склонен согласиться с тем, что вы всегда должны называть Delegate.EndInvoke для предотвращения утечки памяти (даже Джон Скит сказал это!).
Я всегда следил за этим руководством без вопросов, но недавно я реализовал свой собственный класс AsyncResult и увидел, что единственным ресурсом, который может протекать, является AsyncWaitHandle.
(На самом деле это действительно не утечка, потому что собственный ресурс, используемый WaitHandle, инкапсулирован в SafeHandle, у которого есть Finalizer, он добавит давление на очередь финализации сборщика мусора. Тем не менее, хорошая реализация AsyncResult будет только инициализировать AsyncWaitHandle по запросу...)
Лучший способ узнать, есть ли утечка, - это просто попробовать:
Action a = delegate { };
while (true)
a.BeginInvoke(null, null);
Я запустил это некоторое время, и память останется между 9-20 МБ.
Давайте сравним, когда вызывается Delegate.EndInvoke:
Action a = delegate { };
while (true)
a.BeginInvoke(ar => a.EndInvoke(ar), null);
С помощью этого теста память воспроизводится между 9-30 МГ, странно, а? (Вероятно, потому что для выполнения AsyncCallback требуется немного больше времени, поэтому в ThreadPool будет больше делегированных в очереди делегатов)
Как вы думаете... "Миф разорился"?
P.S. ThreadPool.QueueUserWorkItem на сто эффективнее, чем Delegate.BeginInvoke, лучше использовать его для запуска и перезапуска вызовов.