C#托管及未托管對象管理
c#中的對象分為值類(lèi)型和引用類(lèi)型,二者最大的區別在于數據的存儲方式和存儲位置.WINDOWS操作系統使用虛擬尋址系統來(lái)管理程序運行時(shí)產(chǎn)生的數據存放.簡(jiǎn)單的說(shuō),該系統管理著(zhù)一個(gè)內存區域,在該區域中劃撥出一部分出來(lái)專(zhuān)門(mén)存放值類(lèi)型變量,稱(chēng)為堆棧,堆棧采用先進(jìn)后出的原則,將值類(lèi)型變量從區域的最高地址位開(kāi)始向低位地址存儲,先進(jìn)后出,后進(jìn)先出的管理方式保證了值類(lèi)型變量在出了作用域后能即使的清除占用的內存區域,由于堆棧速度快,所保存的數據一般不太大,這部分一般不需要用戶(hù)專(zhuān)門(mén)操作. 值類(lèi)型保存在堆棧匯總, 堆棧有非常高的性能,但對于所有的變量來(lái)說(shuō)還是不太靈活。通常我們希望使用一個(gè)方法分配內存,來(lái)存儲一些數據,并在方法退出后的很長(cháng)一段時(shí)間內數據仍是可以使用的。只要是用new運算符來(lái)請求存儲空間,就存在這種可能性——例如所有的引用類(lèi)型。此時(shí)就要使用托管堆。它在垃圾收集器的控制下工作,托管堆(或簡(jiǎn)稱(chēng)為堆)是系統管理的大內存區域中的另一個(gè)內存區域。要了解堆的工作原理和如何為引用數據類(lèi)型分配內存,看看下面的代
碼:
Customer arabel = new Customer();
這行代碼完成了以下操作:首先,分配堆上的內存,以存儲Customer實(shí)例(一個(gè)真正的實(shí)例,不只是一個(gè)地址)。然后把變量arabel的值設置為分配給新Customer對象的內存地址(它還調
用合適的Customer()構造函數初始化類(lèi)實(shí)例中的字段,但我們不必擔心這部分)。
Customer實(shí)例沒(méi)有放在堆棧中,而是放在內存的堆中。如果我們這樣操作:
Customer newaddress = arabel ;
這時(shí)候,newaddress也會(huì )保存在堆棧中,其值和arabel 相同,都是存儲Customer實(shí)例的堆地址. 知道了這些,我們會(huì )發(fā)現這樣一個(gè)問(wèn)題,如果堆棧中arabel 和newaddress兩個(gè)變量過(guò)期銷(xiāo)毀,那堆中保存的Customer對象會(huì )怎樣?實(shí)際上它仍保留在堆中,一直到程序停止,或垃圾收集器刪除它為止. C#的垃圾收集器如果沒(méi)有顯示調用,會(huì )定時(shí)運行并檢查內存,刪除沒(méi)有任何變量引用的數據.看起來(lái)似乎不錯,但是想想,垃圾回收器并不是時(shí)時(shí)檢查,它是定時(shí)運行,而在這段時(shí)間內如果產(chǎn)生大量的過(guò)期數據駐留在內存中..... 那么或許我們可以通過(guò)調用System.GC.Collect(),強迫垃圾收集器在代碼的某個(gè)地方運行,System.GC是一個(gè)表示垃圾收集器的.NET基類(lèi), Collect()方法則調用垃圾收集器。但是,這種方式適用的場(chǎng)合很少,(難道銷(xiāo)毀一個(gè)對象就讓垃圾回收檢查一便內存嗎?)例如,代碼中有大量的對象剛剛停止引用,就適合調用垃圾收集器。況且垃圾收集器的邏輯不能保證在一次垃圾收集過(guò)程中,從堆中刪除所有過(guò)期數據,對于不受垃圾回收器管理的未托管對象(例如文件句
柄、網(wǎng)絡(luò )連接和數據庫連接),它是無(wú)能為力的。那該怎么做呢?
這時(shí)需要制定專(zhuān)門(mén)的規則,確保未托管的資源在回收類(lèi)的一個(gè)實(shí)例時(shí)釋放。 在定義一個(gè)類(lèi)時(shí),可以使用兩種機制來(lái)自動(dòng)釋放未托管的資源。這些機制常常放在一起實(shí)現,
因為每個(gè)機制都為問(wèn)題提供了略為不同的解決方法。這兩個(gè)機制是:
● 聲明一個(gè)析構函數,作為類(lèi)的一個(gè)成員 ● 在類(lèi)中實(shí)現System.IDisposable接口
下面依次討論這兩個(gè)機制,然后介紹如何同時(shí)實(shí)現它們,以獲得最佳的效果。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。