內(nèi)存泄漏之Event Handler

事件是我們?cè)赪PF開(kāi)發(fā)過(guò)程中使用的非常多的技術(shù),但是如果一不小心就會(huì)發(fā)生內(nèi)存泄漏葡粒,請(qǐng)看下面的Demo份殿。
我創(chuàng)建了一個(gè)簡(jiǎn)單的窗口:

<Window x:Class="MemoryLeak.Example.Example3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Window>

Example3.xaml.cs中的代碼如下:

public partial class Example3
{
    //這里產(chǎn)生一個(gè)大的內(nèi)存占用,約50MB嗽交,用于在任務(wù)管理器看到這個(gè)窗口Show出來(lái)以后卿嘲,進(jìn)程內(nèi)存占用劇增的現(xiàn)象
    private readonly List<string> _bigList = ExampleHelper.BigList();

    public Example3()
    {
        InitializeComponent();

        Application.Current.Exit += Current_Exit;
    }

    private void Current_Exit(object sender, ExitEventArgs e)
    {
        Console.WriteLine(DateTime.Now);
    }
}

內(nèi)存泄漏現(xiàn)象

Example3 window = new Example3();
window.Show();

然后將此window直接關(guān)閉,那么顯然這個(gè)window生命周期結(jié)束夫壁,再無(wú)引用拾枣。執(zhí)行:

GC.Collect();

window占用的50MB內(nèi)存應(yīng)該被回收,然后在任務(wù)管理器中看此進(jìn)程盒让,其內(nèi)存并沒(méi)有被回收梅肤。什么東西阻止了我回收?阻止回收的根本原因是仍然有人引用邑茄!我們來(lái)挖一下姨蝴,深層次的原因在哪里。

源碼分析

window生命周期分析

最關(guān)鍵的代碼在此處:Application.Current.Exit += Current_Exit;這句話表示撩扒,我訂閱了Application的Exit事件似扔,訂閱的完整代碼應(yīng)該是這樣:Application.Current.Exit += this.Current_Exit;,我們知道事件的工作原理是觀察者模式吨些,要實(shí)現(xiàn)觀察者模式就必須有目標(biāo)Target和處理函數(shù)Method,這句話將this作為觀察者模式中的Target炒辉,Current_Exit作為Method豪墅,當(dāng)事件發(fā)生的時(shí)候可以通過(guò)Target調(diào)用Target中的Method,所以Application.Current.Exit += Current_Exit;這句話就將window強(qiáng)引用了黔寇。而Application.Current是靜態(tài)變量偶器,那么就會(huì)造成windowApplication.Current引用,只有Application.Current被回收才能回收window了缝裤。

內(nèi)存泄漏原因深度剖析及解決措施

本質(zhì)的原因就是有更長(zhǎng)生命周期的對(duì)象持有對(duì)你的引用屏轰,造成無(wú)法回收。
上述問(wèn)題談到Application.Current.Exit += Current_Exit;憋飞,這句話造成了對(duì)window的強(qiáng)引用霎苗,所以你不用的時(shí)候手動(dòng)解除一下引用關(guān)系就可以回收了:Application.Current.Exit -= Current_Exit;
說(shuō)到事件處理函數(shù)不得不提匿名函數(shù),我們就本例再換種方式:Application.Current.Exit += (s, e) => { Console.WriteLine(DateTime.Now); };這樣就不會(huì)阻止垃圾回收榛做,而Application.Current.Exit += (s, e) => { Console.WriteLine(this.Width); };唁盏,window就無(wú)法回收了。
匿名函數(shù)到底發(fā)生了什么检眯?為什么有時(shí)會(huì)阻止回收厘擂,有時(shí)不會(huì)?請(qǐng)看我的另一篇文章:《原來(lái)是這樣:C#中的匿名函數(shù) & 閉包(未完成)》

至此事件锰瘸,包括非靜態(tài)事件例如父對(duì)象的事件刽严,子對(duì)象訂閱了”苣或者父對(duì)象的事件處理器是子對(duì)象的:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        Example3 window = new Example3();
        ExampleTextBox.TextChanged += window.TextBox_TextChanged;
        window.Show();
    }
}
public partial class Example3
{
    public Example3()
    {
        InitializeComponent();
    }

    public void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
    }
}

等等都會(huì)造成內(nèi)存泄漏舞萄。
我們知曉了造成內(nèi)存泄漏的根本原因就是還有引用,解決措施就很簡(jiǎn)單了:在不需要的時(shí)候解除引用恕曲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹏氧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子佩谣,更是在濱河造成了極大的恐慌把还,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茸俭,死亡現(xiàn)場(chǎng)離奇詭異吊履,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)调鬓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)艇炎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人腾窝,你說(shuō)我怎么就攤上這事缀踪【幼” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵驴娃,是天一觀的道長(zhǎng)奏候。 經(jīng)常有香客問(wèn)我,道長(zhǎng)唇敞,這世上最難降的妖魔是什么蔗草? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮疆柔,結(jié)果婚禮上咒精,老公的妹妹穿的比我還像新娘。我一直安慰自己旷档,他們只是感情好模叙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著彬犯,像睡著了一般向楼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谐区,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音逻卖,去河邊找鬼宋列。 笑死,一個(gè)胖子當(dāng)著我的面吹牛评也,可吹牛的內(nèi)容都是我干的炼杖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼盗迟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坤邪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起罚缕,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤艇纺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后邮弹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體黔衡,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年腌乡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盟劫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡与纽,死狀恐怖侣签,靈堂內(nèi)的尸體忽然破棺而出塘装,到底是詐尸還是另有隱情,我是刑警寧澤影所,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布氢哮,位于F島的核電站,受9級(jí)特大地震影響型檀,放射性物質(zhì)發(fā)生泄漏冗尤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一胀溺、第九天 我趴在偏房一處隱蔽的房頂上張望裂七。 院中可真熱鬧,春花似錦仓坞、人聲如沸背零。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)徙瓶。三九已至,卻和暖如春嫉称,著一層夾襖步出監(jiān)牢的瞬間侦镇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工织阅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壳繁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓荔棉,卻偏偏與公主長(zhǎng)得像闹炉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子润樱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 靜態(tài)類里面的事件渣触,再普通不過(guò),經(jīng)常使用它來(lái)做全局廣播壹若。但是如果一不小心就會(huì)發(fā)生內(nèi)存泄漏嗅钻,請(qǐng)看下面的Demo:我創(chuàng)建...
    古意昌閱讀 560評(píng)論 0 0
  • 我們經(jīng)常會(huì)在程序中使用DispatcherTimer,但是如果一不小心就會(huì)發(fā)生內(nèi)存泄漏舌稀,請(qǐng)看下面的Demo: 內(nèi)存...
    古意昌閱讀 3,351評(píng)論 1 2
  • 其實(shí)想想啊犬,二十歲的自己真的很傻很天真,雖然已經(jīng)是兩個(gè)孩子的媽壁查,可還是選擇了原諒觉至,選擇了婚姻∷龋可是语御,我們到底是從什么...
    陳珊_6624閱讀 155評(píng)論 0 0
  • 不知道從什么時(shí)候開(kāi)始峻贮,我開(kāi)始找各種理由逃避著現(xiàn)實(shí),高考失利的我并沒(méi)有選擇復(fù)讀应闯,因?yàn)橛X(jué)得那是在浪費(fèi)爸媽的資源纤控,我到了...
    劉稔稔稔閱讀 307評(píng)論 0 0
  • R: 在生氣時(shí),批評(píng)和指責(zé)他人都無(wú)法真正傳達(dá)我們的心聲碉纺。如果想充分表達(dá)憤怒船万,我們就不能歸咎于他人,而把注意力放在...
    意為安閱讀 488評(píng)論 0 1