全局靜態(tài)集合類型的變量的垃圾你給我去死!!!!(本文知識(shí)有誤,請(qǐng)等待8.12晚上的反思)
反思--------不怕丟臉,就怕沒收獲
原來(lái),這篇文章居然成了個(gè)笑話唉。
事大概是這么個(gè)事哈,我看http://bbs.csdn.net/topics/80471342,大概知道了靜態(tài)變量的回收是有限制滴。
而我剛好遇到這么個(gè)業(yè)務(wù),我現(xiàn)在想自己做一個(gè)MMO游戲的服務(wù)端,因?yàn)榉?wù)端需要實(shí)時(shí)模擬每一個(gè)客戶端的記錄 。所以毫無(wú)疑問(wèn)這個(gè)變量要是一個(gè)集合,并且一直在內(nèi)存中。
所以我的代碼是這么寫的
Public static Dictionary<int,Actor> dcActors = new Dictionary<int,Actor>();
可突發(fā)奇想,是不是靜態(tài)集合的類型的變量?jī)?nèi)存回收會(huì)有限制呢??于是寫了下面兩段代碼
非靜態(tài)變量using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { public static void Main(string[] args) { Run(); Wait(); } public static void Run() { B B = new B(); for (int i = 0; i < 10000000; i++) { B.dcA.Add(i, new A()); } B.dcA.Clear(); Console.WriteLine("清掉了"); GC.Collect(); } public static void Wait() { Console.Read(); Console.Read(); Console.Read(); Console.Read(); } } class B { public Dictionary<int, A> dcA = new Dictionary<int, A>(); } class A { public string str = "水水水水水水水水水水水水水水水水水水水水水水水水"; } }
靜態(tài)變量using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { public static void Main(string[] args) { Run(); Wait(); } public static void Run() { B B = new B(); for (int i = 0; i < 10000000; i++) { B.dcA.Add(i, new A()); } B.dcA.Clear(); Console.WriteLine("清掉了"); GC.Collect(); } public static void Wait() { Console.Read(); Console.Read(); Console.Read(); Console.Read(); } } class B { public static Dictionary<int, A> dcA = new Dictionary<int, A>(); } class A { public string str = "水水水水水水水水水水水水水水水水水水水水水水水水"; } }
然后 ,非靜態(tài)變量的那段代碼在哈希表被清掉之后,我截圖看是這樣滴。
而,靜態(tài)變量的哈希表被情調(diào)后,內(nèi)存檢測(cè)工具顯示是這樣滴。
所以,我就信任了這個(gè) 內(nèi)存檢測(cè)工具..... 唉.......。
而我用資源管理器里的東西看內(nèi)存,發(fā)現(xiàn),兩個(gè)代碼都是由600多M(填充1000W個(gè)實(shí)體類) 掉到300多M(全部清空)。
而我在代碼中的類型A里添加析構(gòu)函數(shù)檢測(cè),發(fā)現(xiàn)兩個(gè)代碼在清空的時(shí)候,1000W個(gè)類A都被銷毀了
所以我的教訓(xùn)是
1:在沒有使用到一些特殊的諸如UI,IO,數(shù)據(jù)庫(kù),圖片,事件=.... 等地方的時(shí)候,幾乎可以完全相信.NET的GC的威力。只要你沒有某些代碼沒有死守著對(duì)象不放,GC是一定可以找到垃圾并回收的。靜態(tài)變量當(dāng)然在此列
2:一些個(gè)工具什么的其實(shí)未必要那么信任。自己寫的代碼檢測(cè)才是王道
3:有問(wèn)題就要拿出來(lái)大家一起討論,不怕丟臉,但就怕沒收獲
問(wèn)題
眾所周知,C#比起C++ C 等語(yǔ)言來(lái)說(shuō),最大的好處就是幾乎不用管理內(nèi)存,也就是不用處理‘垃圾’,會(huì)有GC自動(dòng)來(lái)清掃。但我有一個(gè)疑惑就在于,全局靜態(tài)集合型變量的垃圾誰(shuí)來(lái)收?
代碼
如上圖,定義了一個(gè) 哈希表dcA,初始給其填充 1000萬(wàn)個(gè) 對(duì)象A。執(zhí)行該程序,會(huì)發(fā)現(xiàn)1000W個(gè)對(duì)象填充到內(nèi)存里,內(nèi)存會(huì)非常大,打開資源管理器會(huì)發(fā)現(xiàn),這內(nèi)存占了大約600M的樣子。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { public static void Main(string[] args) { Run(); Wait(); } public static void Run() { for (int i = 0; i < 10000000; i++) { B.dcA.Add(i, new A()); } B.dcA.Clear(); Console.WriteLine("清除了"); } public static void Wait() { Console.Read(); Console.Read(); Console.Read(); Console.Read(); } } class B { public static Dictionary<int, A> dcA = new Dictionary<int, A>(); } class A { public string str = "水水水水水水水水水水水水水水水水水水水水水水水水"; } }
可接下來(lái)讓我蛋疼的問(wèn)題是,清除掉了哈希表中的這1000W個(gè)對(duì)象。內(nèi)存...... 內(nèi)存居然還是600多M,居然一點(diǎn)都沒變。
內(nèi)存檢測(cè)工具來(lái)了

圖中說(shuō)的啥
第一圖非常明顯的告訴我,內(nèi)存占用者就是那個(gè)明明已經(jīng)為空的 鍵值對(duì)大哥。一下占了幾百兆。
第二張圖 告訴我,這個(gè)變量不是GC回收的對(duì)象,離 GC root 還有一步之遠(yuǎn)。
所以,祭出GC了
尼瑪內(nèi)存一點(diǎn)都沒減少,有種可能是GC還沒出動(dòng),所以我把代碼改一下,在 B.dcA.Clear(); 收加上 GC.Collect();
可是,這行代碼居然一點(diǎn)作用都沒有。
你說(shuō),全局靜態(tài)集合類型的靜態(tài)變量的垃圾誰(shuí)來(lái)收呢??難倒一直在內(nèi)存中呆著直到死???
感謝 imfunny 給出的一個(gè)小解決方案讓我更加了解了GC的機(jī)制。
簡(jiǎn)單的來(lái)說(shuō)我的問(wèn)題就是:
假如某個(gè)變量是非靜態(tài)變量集合,比如public List<A> aList =new List<A>();
我們給這個(gè)aList填充1千萬(wàn)個(gè)對(duì)象然后清空,內(nèi)存會(huì)馬上會(huì)被回收。
但如果是public static List<A> aList =new List<A>();
我們給這個(gè)靜態(tài)的aList填充1千萬(wàn)個(gè)對(duì)象然后清空,內(nèi)存就絲毫不會(huì)變。
而在我的業(yè)務(wù)需求中,我要求在內(nèi)存中在我需要的時(shí)候一直駐留著List<A>,當(dāng)其中的某個(gè)A的實(shí)例不要了我清掉,
這個(gè)被我清掉的的A的實(shí)例會(huì)被回收掉。
我之前的想法是通過(guò)靜態(tài)的共有的集合類型,即public static List<A> aList =new List<A>();
但后來(lái)發(fā)現(xiàn)我怎么清空都沒用,我業(yè)務(wù)需求又注定不能用 aList=null,這樣的機(jī)制
所以,我想了一個(gè)折中的辦法,即加入這個(gè)aList屬于 B類型,那么我再創(chuàng)建一個(gè)C類型,在C類型中寫一個(gè)單鍵
類,有且僅有一個(gè)B的靜態(tài)實(shí)例。這樣的話我就能實(shí)現(xiàn)我的業(yè)務(wù)需求了
29樓的大俠給出了我的這種思想的代碼,各位前往圍觀啊
答案:
29樓的大俠給出了我的問(wèn)題的答案。各位可以參考一下 這篇博客 http://www.rzrgm.cn/bayonetxxx/archive/2009/06/02/1494728.html。即WeakReference 類的使用。嘿嘿




浙公網(wǎng)安備 33010602011771號(hào)