C# 對象銷燬和垃圾回收

資源鏈接:

IDisposable 接口  https://msdn.microsoft.com/zh-cn/library/system.idisposable(v=vs.110).aspx

c# -- 對象銷燬和垃圾回收                http://www.cnblogs.com/yang_sy/p/3784151.html
WPF中解決內存泄露的幾點提示與解決方法   http://www.cnblogs.com/LastPropose/archive/2011/08/01/2124359.html
淺談C#託管程序中的資源釋放問題          http://blog.chinaunix.net/uid-626379-id-2706280.html
C#如何進行對象的銷燬和資源的釋放?     http://blog.csdn.net/tanliyoung/article/details/1244148


http://bbs.csdn.net/topics/390819462


今天看到一個項目代碼,其中 它 在主窗體一個按鈕事件 中新建了一個模式窗體:

<span style="font-size:14px;">DialogResult result = frm.ShowDialog();</span>
然後在模式窗體執行完畢前給模式窗體frm的兩個屬性賦值:
<span style="font-size:14px;">this._title = model.ScriptTitle;
this._message = model.ScriptMsg;</span>
然後:
<span style="font-size:14px;"> this.DialogResult = DialogResult.OK;</span>
<span style="font-size:14px;"> this.Close();</span>
然後奇怪的是 主窗體居然可以通過 frm.Title,frm.Message 接收到這兩個值?如下:
<span style="font-size:14px;"> if (result ==DialogResult.OK)
                {
                    //表示用戶成功更新了當前節點,刷新數據
 
                    treeView1.SelectedNode.Text = frm.Title;
                    textBox1.Text = frm.Message;
                }</span>

我就疑問了,模式窗體frm不是已經this.close()關閉了嗎? 怎麼還能在主窗體接受到值? 難道模式窗體frm沒有釋放?


回覆於: 2014-06-24 10:27:17    #2 得分:5 

Form.Close後Form裏面的非託管資源是立刻釋放了,只是託管資源到GC.Collect()纔會真正釋放


回覆於: 2014-06-24 10:29:20    #4 得分:10 

嗯,這問題不錯,微軟的解釋是“在以下兩種情況下調用 Close 不會釋放窗體:(1) 窗體是多文檔界面 (MDI) 應用程序的一部分且是不可見的;(2) 您是使用 ShowDialog 顯示的該窗體。 在這些情況下,需要手動調用 Dispose 來將窗體的所有控件都標記爲需要進行垃圾回收。”


回覆於: 2014-06-24 13:13:14  #12 得分:5 
 引用 9 樓 jsjisweet 的回覆:
 Quote: 引用 2 樓 hbu_pig 的回覆:
 Form.Close後Form裏面的非託管資源是立刻釋放了,只是託管資源到GC.Collect()纔會真正釋放

哪些是非託管資源?哪些又是託管資源?


好比你有一個Thread 託管對象,這個對象內部持有這非託管資源,一個內核對象,線程都是操作系統的內核對象,c#的Thread類只是對其作了一個包裝。當你調用thread對象的dispose方法的時候,內核對象被釋放,操作系統回收內核對象。但是你的託管thread對象還被你持有,你還可以訪問它的屬性和方法,但大多數方法和屬性都會拋出objectdisposedexception。
對於window窗體來說也是,window類其實也是對非託管資源的一些封裝。當你調用Close的時候,其實窗體內部的資源也被釋放了,記住任何時候調用Dispose方法,都是即釋放託管資源,也釋放非託管資源。你的問題來了,既然都釋放了,那爲什麼我還可以訪問這個window對象,答案是,被釋放的資源是Window對象使用的資源,而非Window對象本身,你還可以訪問這個Window對象,但是僅僅限於那些不依賴被釋放資源的屬性和方法。不信的話,當你在調用Close之後,再調用Show,你就知道結果了。

回覆於: 2014-06-24 13:14:27  #13 得分:10 
  引用 9 樓 jsjisweet 的回覆:
  Quote: 引用 2 樓 hbu_pig 的回覆:
  Form.Close後Form裏面的非託管資源是立刻釋放了,只是託管資源到GC.Collect()纔會真正釋放
哪些是非託管資源?哪些又是託管資源?


託管資源指的是.NET可以自動進行回收的資源,主要是指託管堆上分配的內存資源。託管資源的回收工作是不需要人工干預的,有.NET運行庫在合適調用垃圾回收器進行回收。 非託管資源指的是.NET不知道如何回收的資源,最常見的一類非託管資源是包裝操作系統資源的對象,例如文件,窗口,網絡連接,數據庫連接,畫刷,圖標等

回覆於: 2014-06-24 17:35:20  #14 得分:3
this->Close(); // this.Close();
// 首先調用對象的終結器( Finalize ),也就是傳說中的( ~virtual className )析構函數(C# / C++)
// 不過這裏被釋放掉的是非託管資源,並等待調用對象繼承自( IDisposable )接口的( Dispose )方法
// 前提是你自身已經實現( IDisposable ),在( Dispose )方法中會設置GC.SuppressFinalize(this)
// 禁止GC再次調用( Finalize ),通知GC進行回收( GC.Collect ),不過並不不是立即會被回收
// 如果你想立即回收再C#裏面那是不可能,當然在C++/CLR裏面可以立即回收Net/Win32資源
// 使用到delete / delete[]關鍵字

回覆於: 2014-06-24 18:23:37  #15 得分:7 

// 其次我想說Net的內存進行回收並非真正是被回收,在GC進行回收時實際上是進行的內存清零(Zero)操作
// 首先Net在程序運行時則自動在內存中分配一塊區域用於Net程序的內存模塊,根據程序所需內存重進行
// 內存申請,實際上Net在分配內存時所分配的函數爲HeapAlloc/GlobalAlloc/LocalAlloc,沒有叫做棧這個
// 概念,棧不過是內存中一塊受保護區域,能夠完成他的函數只有HeapAlloca 
// VirtualAlloc在虛擬內存堆中分配,不過根據我研究Net內存申請形式時,已掐斷這個申請概念,Net
// 不可能再虛擬內存中進行申請,所以能夠可選的只有 堆棧/全局/局部 分配申請
// Net對象在通過new關鍵字創建時Net在Net堆上的維指針會向下移動,因爲這是Net提前申請好
// 的內存塊只需要向下進行移動hMem指針即可,Net在內存中分配的方式是連續的,我相信用C#玩指針的
// 人因該會注意到,當然我不是說的IntPtr指針,而是C系列語言通用指針*,其次在Net程序打斷點掐斷
// 可以看見(返彙編)面板代碼ASM/ARM嵌入式代碼原型,其中(Rsp)這個點我相信因該屬於Net指針在內存中欲分配維指針

// 其次深討JIT虛擬機是如何解釋字節代碼並讓進程執行的,我稍略有研究
// JIT虛擬機屬於動態將IL元元素計算爲Byte字節代碼通過遠程嵌入式彙編技術進行調用,所以在IL代碼原型中所有
// 的一切皆爲方法體,而不是在C#可見得屬性事件等等,不過我曾利用C#對自身進行動態嵌入式彙編技術,不過答案
// 有些讓我無法接受,( 內存寫入錯誤,因爲這是一塊受保護內存區域 ),當然我對C++/易語言/EPL程序進行過遠程彙編
// 答案是可行,彙編/嵌入式 不過如今玩半年多C#能夠記下的機器代碼早已經忘得差不多,不過也無所謂並不打算
// 從事C++更不打算做ARM,我可以給於一些原型幫助你們理解遠程彙編,可以說本地彙編是最簡單的尤其是靜態彙編只需要在
// _asm{ 機器代碼 };編譯前置入則可以,如果是動態彙編必須申請一塊內存區域作代碼的實現塊,將彙編代碼計算出對應的
// 字節代碼寫進,並通過CallWindowProc調用匯編代碼,如果是遠程彙編,我比較喜歡用 VirtualAllocEx 在其他進程
// 申請虛擬內存,使用OpenProcess(打開進程)搭配WriteProcessMemory(寫到內存)並調用CreateRemoteThread(在另一進程中
// 建立線程線索),前提是GetModuleHandleA加載模塊User32.DLL並通過GetProcAddress獲取到的CallWindowProcA函數指針
// hRemoteThread = CreateRemoteThread (進程句柄, 0, 0, CallWindowProc函數指針, 彙編遠程代碼指針, 0, 0)// NULL=0
// 其次則是WaitForSingleObject(hRemoteThread, -1)(監測一個對象),等待遠程彙編代碼調用執行完畢


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章