麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

【.NET深呼吸】清理對(duì)象引用,有一個(gè)問(wèn)題容易被忽略

2019-11-14 16:10:33
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

大家知道,托管代碼一個(gè)重要的特點(diǎn)是自動(dòng)管理內(nèi)存,即我們常說(shuō)的垃圾回收機(jī)制,那些高大上的理論我就不重復(fù)了,有興趣的朋友可以翻書(shū)。我這個(gè)有個(gè)毛病——不喜歡很嚴(yán)肅地去說(shuō)一些理論的東西,所以我不多介紹了。

一般而言,當(dāng)代碼執(zhí)行超出某個(gè)變量的有效范圍后,或者不再引用某個(gè)對(duì)象實(shí)例時(shí),該實(shí)例會(huì)發(fā)生析構(gòu),垃圾回收器很可能就要清理門戶了,當(dāng)然也可能不是馬上清理,也許會(huì)過(guò)一會(huì)兒再清理。

對(duì)于一些要自定義進(jìn)行清理操作的類,我們會(huì)采取以下方案:

1、寫(xiě)上析構(gòu)函數(shù),在析構(gòu)函數(shù)中清理。

2、實(shí)現(xiàn)IDisposable接口,并實(shí)現(xiàn)Dispose方法,在方法中編寫(xiě)自定義清理代碼。當(dāng)該類型被實(shí)例化后,最后不再使用時(shí)會(huì)調(diào)用Dispose方法清理,如果順利清理,最后還會(huì)調(diào)用類型的析構(gòu)函數(shù)。通常,如何實(shí)現(xiàn)了IDisposable接口,就不必再寫(xiě)上析構(gòu)函數(shù)了。如果希望Dispose方法被自動(dòng)調(diào)用,可以在實(shí)例化對(duì)象的代碼包裝在using語(yǔ)句塊中,當(dāng)執(zhí)行完using塊時(shí)會(huì)自動(dòng)調(diào)用Dispose方法。

 

可能有人笑了,老周,你太逗了,這些基礎(chǔ)知識(shí)誰(shuí)不知道?當(dāng)然,我說(shuō)上面那些內(nèi)容是為了繞個(gè)小圈子,以便進(jìn)入主題。于是,我產(chǎn)生了一個(gè)疑問(wèn):是不是存在某些情景下,可能導(dǎo)致對(duì)象實(shí)例不會(huì)被回收呢?就算你調(diào)用了Dispose方法,就算你把變量設(shè)為null來(lái)解除引用,就算你調(diào)用GC類的方法來(lái)回收……

經(jīng)過(guò)老周測(cè)試,還真有這種情況,而且很多朋友都很有可能會(huì)忽略,甚至在意識(shí)認(rèn)知上誤認(rèn)為對(duì)象實(shí)例已經(jīng)被回收,而實(shí)際上是沒(méi)有回收的。

 

我簡(jiǎn)單說(shuō)一下這種情形:

比如有一個(gè)靜態(tài)類(靜態(tài)類的成員必是靜態(tài)的)A,里面有靜態(tài)事件。隨后在其他類的實(shí)例中處理A類的靜態(tài)事件,并且處理事件的方法就位于這個(gè)實(shí)例對(duì)象上……

不急,我們還是看真實(shí)的例子吧。假如我定義了一個(gè)靜態(tài)類MyChecker,它里面有個(gè)靜態(tài)事件CheckEvent。

    public static class MyChecker    {        #region 靜態(tài)事件        public static event EventHandler CheckEvent;        #endregion        public static void CallEvent()        {            if (CheckEvent != null)            {                CheckEvent(new object(), EventArgs.Empty);            }        }    }

只要CallEvent方法被調(diào)用,CheckEvent事件會(huì)被引發(fā)。

 

然后,定義另一個(gè)類SampleClass,并在該類中處理剛才MyChecker中的靜態(tài)事件。

    class SampleClass:IDisposable    {        public SampleClass()        {            MyChecker.CheckEvent += MyChecker_CheckEvent;        }        void MyChecker_CheckEvent(object sender, EventArgs e)        {            new Form2().Show();        }        ~SampleClass()        {            System.Diagnostics.Debug.WriteLine("/n看,析構(gòu)函數(shù)調(diào)用了。/n");        }        public void Dispose()        {            //……        }    }


在類的構(gòu)造函數(shù)中,附加CheckEvent事件的處理,處理方法名為MyChecker_CheckEvent。

可能大家已經(jīng)發(fā)現(xiàn),老周寫(xiě)的SampleClass類有點(diǎn)恐怖氣息,既實(shí)現(xiàn)了Dispose方法,怎么又寫(xiě)了析構(gòu)函數(shù),我這里寫(xiě)上析構(gòu)函數(shù)是為了驗(yàn)證類的實(shí)例是否真的被清理,如果實(shí)例真的被回收,那么Debug類會(huì)在“輸出”窗口中輸出提示,如果沒(méi)有提示輸出,說(shuō)明類的實(shí)例還霸占著內(nèi)存。

接下來(lái)測(cè)試一下。

            SampleClass sc = new SampleClass();            await Task.Delay(10 * 1000);            sc.Dispose();            sc = null;            GC.Collect();


實(shí)例化SampleClass后,然后Delay會(huì)暫停10秒,10秒鐘過(guò)后會(huì)調(diào)用Dispose方法,并設(shè)置變量為null引用,我害怕不能及時(shí)清理,連GC.Collect方法也用上了。

而在等待這10秒期間,可以調(diào)用靜態(tài)類的CallEvent方法來(lái)引發(fā)靜態(tài)事件CheckEvent。

MyChecker.CallEvent();

按照一般理解,在10秒鐘后,SampleClass實(shí)例應(yīng)該被清理,并且在“輸出”窗口會(huì)輸出提示。

好,現(xiàn)在試一下。

……

實(shí)驗(yàn)結(jié)果表明,輸出 窗口中連鴨毛都沒(méi)有輸出,這說(shuō)明10秒鐘后,SampleClass實(shí)例根本沒(méi)有發(fā)生析構(gòu)。于是又出問(wèn)題了,這是怎么回事?SampleClass實(shí)例不是不存在引用了嗎,怎么不發(fā)生析構(gòu)?

其實(shí)我們忽略了一點(diǎn):靜態(tài)事件CheckEvent還跟SampleClass實(shí)例的方法綁定著呢,實(shí)質(zhì)上,雖然將變量設(shè)為null,可是SampleClass實(shí)例中的MyChecker_CheckEvent方法還被靜態(tài)類中的靜態(tài)事件引用著,所以不會(huì)被回收。不知道你明白了沒(méi)。

這個(gè)問(wèn)題很多朋友在實(shí)際開(kāi)發(fā)中都會(huì)忽略,還得意地以為Sample實(shí)例真的被回收了,實(shí)際上實(shí)例不會(huì)被回收,除非程序結(jié)束。因?yàn)镸yChecker是靜態(tài)類,不基于實(shí)例。如果MyChecker不是靜態(tài)類,那么當(dāng)MyChecker的實(shí)例釋放后,SampleClass實(shí)例就可以被釋放了。

那么,如何解決呢?很簡(jiǎn)單,只要在SampleClass類的Dispose方法中解除靜態(tài)事件與方法的綁定即可,這樣的話,靜態(tài)事件就不再引用實(shí)例中的方法成員了,此時(shí)實(shí)例就可以發(fā)生析構(gòu)了。

        public void Dispose()        {            MyChecker.CheckEvent -= MyChecker_CheckEvent;        }

 

這個(gè)例子研究,告訴我們:在類實(shí)例中處理靜態(tài)事件時(shí)一定要小心。

本示例的源碼下載:http://files.VEVb.com/files/tcjiaan/refsample.zip

好了,今天就扯到這里吧。

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 91短视频在线播放 | 亚洲草逼视频 | 末成年女av片一区二区 | 久久精品亚洲国产奇米99 | 国产成年人视频 | av成人一区二区 | 失禁高潮抽搐喷水h | 成人在线视频一区 | chinesexxxx刘婷hd 国产91在线播放九色 | 毛片在线视频在线播放 | 91羞羞 | 麻豆视频国产在线观看 | 性生活视频一级 | 毛片在线播放视频 | 成片免费观看视频大全 | 国产一国产一级毛片视频在线 | 成人在线视频一区 | 欧美视频国产 | 久久亚洲精品国产 | 视频一区二区三区视频 | 黄色片快播 | 毛片三区| 一区二区三区视频在线播放 | 国产精品片一区二区三区 | 久久91精品 | av在线等| 国产精品亚洲一区二区三区在线观看 | 久久艹综合 | 草草久 | 国产亚洲精品一区二区三区 | 国产中出在线观看 | 国产xxxx岁13xxxxhd | 久色精品视频 | 久久久国产精品电影 | 免费午夜视频 | 日韩精品久久久 | 国产成人在线网址 | 久国久产久精永久网页 | 精品久久久久久亚洲精品 | 久久羞羞视频 | 毛片毛片免费看 |