C# 中如何有效地釋放內存?

我建立了一個棧(Stack),然後存入了許多數據,再將這些數據一一Pop出來,最後這個棧為空棧,但分配給它的內存空間並沒有釋放。還有比如說實例化一個對象,這個對象我不用了,我要釋放掉它,怎麼做?

Dispose我也試過了,沒用,或者說無法做到強制釋放。

object=null我也試過了,然後調用GC來回收,還是回收不掉。

另外如何銷毀基本變數類型?比如說有一個int型的數據,我不要了,我要銷毀它,又該怎麼做?

對C#的內存管理機制我真的是醉了。。。。

----------------------------------------------分割線---------------------------------------

好吧,很多人都是來吐槽的,吐槽也就吐槽吧。

關於為什麼我要手動銷毀基本變數類型,因為有時候我真不知道它的生命周期究竟到什麼時候結束,在某些多次函數調用,或者遞歸調用中,我希望能顯式地釋放掉某些基本變數。

關於我為什麼一定要立即回收它的內存,因為我在建立一顆巨大的樹的過程中,在生成節點的過程中,產生了一些過度變數,這些過度變數在最後的節點生成之後便沒有用了,我需要對它們進行回收以使得有足夠的空間建立儘可能多的節點。

最後,我自己嘗試了一下,既然是引用型的,那通過指向null的方式似乎可以釋放掉內存空間,基本的嘗試也成功了。不過顯然的,有時候會有多個引用指向同一塊內存空間,此時想要釋放掉這塊空間就比較困難了。

另外,我知道石頭拿來擦屁股不好使,可我就是想知道,石頭能不能拿來擦屁股,不行么?各位乎友別浪費時間來吐槽了,如果真有什麼,可以有效地強制釋放內存的方式,再回答吧。

----------------------------------------------分割線---------------------------------------

被建議明確問題了,那就明確一下吧。在C#中有沒有方法可以強制而有效地釋放某變數所引用的內存空間。


如果你不信任GC,你就不應該用託管對象,進而C#這種BCL中99.9%的類型是引用類型的語言都不應該用。

如果你信任GC,就別管這些破事兒。

最後,如果你連int怎麼回收都不知道,應當重新溫習基礎課程。


這種C# 101的問題也要問,我也真的是醉了……


樓主該用C/C++的,這樣比較符合你的習慣吧。


看來題主的問題很多啊。

1、值類型、引用類型、對象的位置

值類型的對象可以存在於託管堆(譬如,當它被裝箱後,或者被匿名委託捕獲了)或者棧上。引用類型的對象只能存在於託管堆上,引用類型的引用可以存在於託管堆(譬如被匿名委託捕獲了)或棧上。

2、棧上的釋放

如果一個棧上存儲的對象超過了作用域,則它被釋放。

3、託管堆上的釋放

託管堆上的對象可能永遠都不被釋放(直到程序結束),因為 GC 的意義是模擬一個內存無限的環境,只要當前內存還夠用,GC 可以永遠不執行垃圾清理任務。當內存不夠的時候,託管堆上的不可達的東西將會有機會被調用 Finalizer 後,被釋放佔用的空間。

不可達可以如下定義:如果對象 A 的某個欄位引用了對象 B,或者 A(作為一個引用類型變數)引用了 B,或者委託 A 捕獲了 B,則建立 A 到 B 的邊。如果從某個棧上的東西或靜態成員到 X 有一條路,則 X 可達。不是可達的是不可達的。

4、關於題主提到了把引用設為 null

首先,如果 X 只有一個引用,你把它所引用的改為 null 之後,X 是不可達。但是不可達不一定會被垃圾收集,這時你可以使用 GC.Collect 來強迫收集,為了確保收集效果,你可以多次調用。

第二種情況,除了你「掌控」的 X 的某個引用外,還有別的地方在引用 X,那你很可能無法強迫 X 被收集,否則為了保持一致性,其他引用 X 的必須都被撤銷對 X 的引用,但是這樣做可以破壞其他地方的一致性,導致整個程序壞掉。對此,一種策略是在某些 applicable 的地方使用 WeakReference。

5、Dispose

Dispose 是為了釋放非託管資源準備的。譬如有一個文件類 File,底層實現是保存一個 IntPtr 作為文件的句柄,因為 File 對象釋放不確定,所以我們讓 File 實現 IDisposable,Dispose 方法將會關閉這個文件並讓這個 File 對象處在不可用狀態。也就是說,Dispose 之後 File 對象不再持有這個文件的訪問權,但是 File 對象本身不一定被 finalize 或收集。


C#的內存管理機制就是【你別管】


int類型的數據內存需要你管?

生命周期結束後 會自動釋放的啊

例如

void add()

{

int a =10;

console.writeline(a);

}

add方法結束後 a的生命周期也隨之結束 會被自動釋放。。

棧內存不是由你來管理的

最後 c#基本不需要你來管理內存

最多看看using的用法。

非專業c#程序員作答。。


為什麼要管,對象大到不放就oom?


1.你想要的是GC.Collect():

2.別用這句。讓GC自己玩兒。


有gc你還管這麼多…少年還是寫cpp比較痛快…

還有int類型釋放,難道你真的手動干過這事?


題主大談內存管理,Dispose,GC這些東西,卻唯獨對概念和基礎視而不見。

從中學開始,老師就反覆強調概念的重要性。

如果之前略過了基礎書籍,還是建議題主找來溫習一下,不是所有的入門都是可以跳過的。

比如棧變數是如何釋放的。


unsafe

{

.. as you like..比如假設下面的代碼是正確的

....

int* val = new int(...)

....

delete val;

}

之所以我說假設上面的代碼是正確的,是因為我是來吐槽lz的,因為c++都不帶這麼寫的。


「另外如何銷毀基本變數類型?比如說有一個int型的數據,我不要了,我要銷毀它,又該怎麼做?

對C#的內存管理機制我真的是醉了」

我是來看這句話的

醒醒吧,醉有什麼用,沒文化就只有多讀書...


C#堆上的內存釋放大家已經講的很清楚了(就是引用類型的資源)。棧上的資源是當你創建變數的時候就會分配內存(即壓棧),當你使用完之後會有個出棧的過程,關於壓棧和出棧的具體方式可以自行百度,大體來說就是先入後出,這就是為什麼你在方法的for循環中創建的變數不能在循環外使用,因為用完之後就執行了出棧的過程。值類型相互賦值是新開空間然後放值,而引用類型只是讓兩個變數指向同一塊內存空間了而已。


反正我是相信gc,信著信著程序就崩了


為什麼要多使用局部變數,因為局部變數的依存關係比較簡單,跳出當前邏輯塊就完成使命了。當GC明確它工作已經結束,並且沒有其它任何對象引用時,就是GC粉末登場的時候了。反之,當一個對象被其它對象或和方法引用時,即使你玩了命去銷毀它,GC也不會理睬你。也可以從事件綁定和事件委託中感悟下,當你委託物業幫你簽收快遞後,你可以在小區消失了,否則,你需要等快遞員到來,不管等多久,你是否有事干,但是,你不能消失。


推薦閱讀:

如何評價微軟推出的 .NET Native?
如何評價 JetBrains 將要推出的跨平台 C# IDE: Rider?
C#的Delegate 為什麼沒在其他主流語言中普及?
請問wpf在設計界面時,是使用blend可視化設計,還是直接編寫xaml代碼呢?
如何看待 .NET Native,真能達到 C++ 的性能、C# 的生產效率嗎?

TAG:信息技術IT | 內存管理 | C# | C#編程 |