2010-02-09 4 views
4

Могут ли делегаты вызывать утечки памяти?Могут ли делегаты вызывать утечки памяти?

Я имею в виду, например, если класс A содержит ADelegate, а последний указывает на BMethod (класс B), может ли это предотвратить сбор классов класса A или B GC?

Если это так, как мы «свободные» делегаты (установка ADeletate = Nothing/нуль?)

Как вы прокомментируете это один:

//Class A Finalize, containing ADelegateInstance as ADelegate' 
protected override void Finalize() 
{ 
    ADelegateInstance = 
     (ADelegate)System.Delegate.RemoveAll(
      ADelegateInstance, ADelegateInstance); 
    ADelegateInstance = null; 
    base.Finalize(); 
} 

'Class A Finalize, containing ADelegateInstance as ADelegate' 
Protected Overrides Sub Finalize() 
    ADelegateInstance = _ 
     CType(System.Delegate.RemoveAll(ADelegateInstance, ADelegateInstance), _ 
      ADelegate) 
    ADelegateInstance = Nothing 
    MyBase.Finalize() 
End Sub 

ответ

8

Да, ссылка будет остаться в живых, если не отказаться от событие:

someObject.SomeEvent -= SomeDelegate; 
+0

Что делать, если у меня есть большой сложный объект с несколькими подписчиками делегатов/unsubscriptions, наконец, в Dispose этого объекта. Я хочу «позволить умереть» всем ссылкам с этим делегатом. – serhio

+1

Тогда вы можете реализовать IDisposable. –

+1

Да, и что мне следует написать в методе Dispose для этого делегата. , может быть, 'System.Delegate.RemoveAll (myDelegate, myDelegate)' поможет? – serhio

2

AFAIK, контекст, что закрытие/делегаты относится к действительно могут не быть мусор, пока закрывающим/делегата по-прежнему ссылается - otherwis e он потеряет свой контекст.

Взяв пример для этого answer, мы видим, что делегат может ссылаться на переменную inneri в контексте объекта. Таким образом, объект, который фактически содержит inneri, не может быть собран в мусор, пока делегат больше не ссылается, в этом случае до сборамусора.

for (int i = 0; i < 7; i++) 
{ 
    var inneri = i; 
    Button newButton = new Button(); 
    newButton.Text = "Click me!"; 
    newButton.Click += delegate(Object sender, EventArgs e) 
    { 
     MessageBox.Show("I am button number " + inneri); 
    }; 
    this.Controls.Add(newButton); 
} 

Похожие сообщения:

+0

Другими словами, вы имеете в виду, что B не будет собираться до тех пор, пока ADelegate указывает на это? .. – serhio

+0

Да, я думаю, это так – ewernli

1

Если A содержит делегат функции в Б, то А не будет разрушена с помощью GC ,

Это хорошая идея всегда ставить «mydelegate - = B.method» каждый раз, когда вы пишете «mydelegate + = B.method».

Хотя это не настоящая утечка памяти, поскольку объекты все еще могут быть достигнуты.

2

Просто наличие справки недостаточно, чтобы вызвать утечку памяти. Рассмотрим следующее.

Если поток порождает 3 объекта (где -> обозначает ссылку), А -> В -> С -> A

Если A не ссылается нити, все собраны. Круглые справки рассматриваются ГК.

Однако это также означает, что если делегат содержит ссылку на объект и этот объект с делегатом по-прежнему ссылается, функция делегата не будет очищена.

Это дало бы следующие рекомендации ниже.

A - (объект с делегатом) B - объект, содержащий ссылку на функцию.

Когда A выпадает из сферы действия, тогда B будет.

0

Была ситуация, когда в приложении ASP.NET использовался один синглтон. И почему-то он подписывался на события контроля. Тот факт, что это был синглтон (содержащий ссылку на себя), не позволял GC собирать его, с другой стороны, что singleton никогда не удалял подписки на контрольные события. Это вызвало постоянный рост потребления памяти: элементы управления, используемые для обслуживания одного запроса, который не очищается GC из-за существующей ссылки из singleton, новые элементы управления, созданные для каждого нового запроса.