1. 程式人生 > >C#使用List.Clear()方法可以讓GC回收記憶體嗎?

C#使用List.Clear()方法可以讓GC回收記憶體嗎?

問題:我現在有一個list,裡面放了若干物件,因為業務需要,程式執行後根據使用者需求,要把list清空,再裝入新的東西,每一次用之前都會清空它,然後裝入新的東西,請問,記憶體是否會洩漏?測試:我設計一個list,清空用clear方法,裝入新東西用add(new obj)。
public void GameInit()
        {
            PlayerCnt = 0;
            PlayerList.Clear();
            PileCnt = 0;
            Pile.Clear();
            DisPileCnt = 0;
            DisPile.Clear();
        }

        public void GameStrat()
        {
            GameInit();
            //準備新牌堆,洗牌
            PileCnt = Card.DeckLength;
            List<short> sort = new List<short>();
            for (short i = 0; i < PileCnt; i++)
            {
                sort.Add(i);//0-207
            }
            Shuffle(sort);
            for (short i = 0; i < PileCnt; i++)
            {
                Pile.Add(new Card(Card.Deck[sort[i]]));
            }
        }

使用按鍵呼叫這個方法,每一次呼叫迴圈10w次。
//menu-操作-重啟遊戲 的 事件
        private void Menu_Restart_click(object sender, RoutedEventArgs e)
        {
            int i = 0;
            for (; i < 100000; i++) 
            {
                GameInst.GameStrat();
            }            
            Console.WriteLine("Debug"+i);
        }


通過工作管理員檢視記憶體狀態。剛開啟app:按下一次按鍵,執行10w次多次按下按鍵,實驗次數大於10次實驗結果表明,C#的GC對於本案例有較好的記憶體控制,第一次執行之後有記憶體上升,之後記憶體消耗非常穩定。分析,本例中,list中新增的物件為Card,每一次新增Card都是通過new的方法建立一個新的Card。Clear只是清空了list中對於這個Card物件的引用,並沒有對每一張Card本身引用做null,但是,根據GC的官方資訊,有兩方面,1、每一張new出來的card只有list可以引用,clear之後,引用計數變為0,認為是垃圾。2、每一張new出來的card從list中移除後,從程式的資料樹根就無法再次通過直接“爬樹”的方法訪問到,成為了程式資料樹中不存在,但是總資料等級表中存在的東西(new一次GC會額外做一次登記),這樣就會被認為是垃圾。

新的問題來了,我這個演算法中有一個洗牌演算法,洗牌演算法原理參照我的上一篇blog

這個洗牌演算法程式碼如下:

public static void Shuffle(List<short> list)
        {
            int length = list.Count;
            short tmp, rdtmp;
            Random rd = new Random();
            for (int i = 0; i < length; i++)
            {
                rdtmp = (short)rd.Next(i, length);
                //Console.WriteLine(i + ": " + rdtmp + " ");
                tmp = list[rdtmp];
                list[rdtmp] = list[i];
                list[i] = tmp;
            }
            //rd = null;
        } 

這個裡面有一個問題,每一次執行洗牌演算法都需要一個random物件

Random rd = new Random();

執行10w次就是new了10w次,從上面的記憶體分析可以看出,這個也被很好的控制了。

具體分析為,每一次new都生成了一個物件,然後每一次執行這段程式,rd都在不斷的指向新的random物件,之前的random物件都變成了野的物件,因此,GC也能通過上述的兩種方法發現老的random物件,實現回收,所以最後的

            //rd = null;

我直接註釋掉了,因為不需要。

所以,放心的new吧。不用管記憶體回收的事情。

爽!