Одной из частых причин утечек памяти в .Net являются обработчики событий, которые никогда не удаляются из своих исходных объектов.
Вызовет ли этот код WCF утечку памяти или лямбда тоже выйдет за пределы области видимости, что позволит собирать как прокси-класс, так и обработчик?
void AMethod()
{
WCFClient proxy;
proxy = new WCFClient();
proxy.RemoteOperationCompleted += (sender, e) => proxy.Close();
proxy.Open();
proxy.RemoteOperationAsync();
}





Этот объект умрет ... он будет очищен.
Не забывайте, что lamda не делает ничего особенного ... это трюк компилятора (так что просто предположите, что это нормальный + = SomeDelegate).
Кроме того, метод «Close» (я не знаю, почему они не сделали его IDisposable) очистит все остальное, что было оставлено открытым.
Не забывайте, что прокси-серверы неправильно реализуют IDisposable. Если произойдет ошибка, приведенный выше код не очистит соединение, и дескриптор останется до закрытия родительского процесса.
Вот мой тест - обратите внимание на явное значение proxy для null в лямбда-выражении - без него WeakReference живет и, следовательно, вероятна утечка:
public class Proxy
{
private bool _isOpen;
public event EventHandler Complete;
public void Close()
{
_isOpen = false;
}
public void Open()
{
_isOpen = true;
}
public void RemoteOperationAsync()
{
if (!_isOpen)
throw new ApplicationException();
Thread.Sleep(1000);
if (Complete != null)
Complete(this, EventArgs.Empty);
}
}
public static class Program
{
public static void Main()
{
WeakReference wr = null;
{
var proxy = new Proxy();
proxy.Complete += (sender, e) =>
{
proxy.Close();
wr = new WeakReference(proxy);
proxy = null;
};
proxy.Open();
proxy.RemoteOperationAsync();
}
GC.Collect(GC.GetGeneration(wr));
GC.WaitForPendingFinalizers();
Console.WriteLine("[LAMBDA] Is WeakReference alive? " + wr.IsAlive);
}
}
Контекст, в котором определена lamdba, будет захвачен и, следовательно, «выживет» в классе закрытия, созданном компилятором (вы можете увидеть их с помощью Reflector) - так что ваш прокси тоже. Используйте слабый обработчик событий или напишите код для отмены регистрации. Но в этом случае вы не можете использовать лямбда-выражение.
Разве это не потому, что текущая область действия метода еще не развернута (поэтому GC не будет их очищать)? Поместите их в метод
GC.Collectи проверьте запись как поле в Main. Безproxy = nullне живо.