Могут ли делегаты вызвать утечку памяти? - PullRequest
4 голосов
/ 09 февраля 2010

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

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

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

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

//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

Ответы [ 5 ]

8 голосов
/ 09 февраля 2010

Да, ссылка останется в силе, если вы не отписаться от события:

someObject.SomeEvent -= SomeDelegate;
2 голосов
/ 09 февраля 2010

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

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

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

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

Это даст вам следующее.

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

Когда А выходит за пределы области видимости, Б. стремится к.

2 голосов
/ 09 февраля 2010

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

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

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);
}

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

1 голос
/ 09 февраля 2010

Если A содержит делегата функции в B, то A не будет уничтожен GC.

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

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

0 голосов
/ 09 февраля 2010

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

...