2017-01-08 93 views
0

我在這裏https://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/看着中介原型。WPF的WeakReference和GC

作者指出「我的第一個想法是在WeakReference中存儲對Action的引用,由於垃圾收集器會丟棄僅由WeakReference對象引用的對象,所以似乎這會做到這一點不幸的是,並不那麼簡單,這種方法的問題是GC會拋棄Action實例,因爲它只被WeakReference引用!

我的問題是,而不是使用「的引用到行動」,爲什麼「給MethodInfo的參考」的伎倆?我假設也應該收集methodinfo。

在此先感謝。

+0

@Rob是的,我同意你的最後一句話。然而,我感到困惑的是,作者暗示如果您在WeakReference中保留對它的引用(我是對的?),那麼爲什麼要保留對MethodInfo的引用? –

回答

1

我的問題是,而不是使用「對Action的引用」,爲什麼「對MethodInfo的引用」有訣竅?我假設也應該收集methodinfo。

不,這不是真的MethodInfo vs Action這個技巧。這是別的,但我不得不承認,這篇文章寫得不好,可能會令人困惑。讓我試着解釋一下。

活動和GC

假設你有一個事件類叫做Click。類是:Button 比方說,你有另一個類訂閱事件從Button這樣的:

public class Subscriber1 
{ 
    public Subscriber1(Button button) 
    { 
     button.Click += ClickHander; 
    } 

    private void ClickHander(object sender, EventArgs e) 
    { 
     // ... 
    } 

    public void UnSubscribe() 
    { 
     button.Click -= ClickHandler; 
    } 
} 

現在如何按鈕類知道是單擊按鈕時誰通知?那麼,它會保留所有已訂閱的類的引用。所以在上面的例子中,它將持有對Subscriber1類實例的引用。每當按鈕被點擊時,它將通知Subscriber1的實例。所以,如果我們這樣做,會發生什麼:

subcriber1Instance = null; 

會發生什麼事是,如果button實例仍然活着,GC將不會收集subscriber1Instance。爲什麼?因爲它的根源:button實例持有對其的引用。這就是爲什麼我們應該做這個:

subscriber1Instance.UnSubscribe(); 
subcriber1Instance = null; 

在現實Subscriber1應該實現IDisposable並做退訂那裏,但這個答案的關鍵不在於。所以我保持簡單,所以我們不會失去焦點。

當我們取消訂閱button實例的Click事件時,subscriberIntance不再是根源,它可以由GC清理。

那麼,什麼是文章在做什麼?

在這篇文章中,作者試圖解決開發人員忘記取消這一問題,並因此導致內存泄漏問題。請注意,這是一種方式:只有當發佈者超過訂閱者時,纔會保持訂閱者活着,而不是相反。因此,如果發佈者準備好GC,訂閱者將無法保持活動狀態。

基本上,作者所說的是訂戶不應該直接訂閱該事件,因此它不會導致button對其進行嚴格引用。相反,用戶應從WeakReference派生,並在訂閱時將其傳遞給button。就像這樣:

private class WeakSubscriber1 : WeakReference 
{ 
    public WeakSubscriber1(Subscriber1 target) : base(target) { } 

    public void ClickHander(object sender, EventArgs args) 
    { 
     Subscriber1 b = (Subscriber1)this.Target; 

     if (b == null) 
     { 
      Button c = sender as Button; 

      if (c != null) 
      { 
       c.MyEvent -= new EventHandler(this.ClickHandler); 
      } 
     } 

     else 
     { 
      b.Handler1(sender, args); 
     } 
    } 
} 

要使用上面的會是這樣:

Subscriber1 sub1 = new Subscriber1(); 
WeakSubscriber1 weak = new WeakSubscriber1(sub1); 
Button button = new Button(); 
button.Click += weak.ClickHandler(); 

現在button是一家控股弱引用。這意味着當sub1爲空並且button觸發該事件時,則weak將檢查sub1是否爲空。如果是,則會檢查button是否仍然存在。如果兩者都是真的,那麼它將退訂。現在sub1不再訂閱button.Click,因此GC可以收集它。

+0

Rob你有沒有機會閱讀那篇文章中鏈接的文章?它是[這裏](https://blogs.msdn.microsoft.com/greg_schechter/2004/05/28/simulating-weak-delegates-in-the-clr/)。不同之處在於第一篇文章試圖使用相同的想法,但在中介模式中。至少這是我閱讀他們時收集的內容。謝謝。 – CodingYoshi

+0

@CodingYoshi謝謝你的詳細解釋。現在我完全理解作者想要做什麼。但是我感到困惑的是,作者暗示,如果您在WeakReference中保留對它的引用,那麼Action將會被GCed,那麼爲什麼要保留對MethodInfo的引用的作用,它不應該被GCed? –