2017年9月11日 星期一

C# / CLR : 關於集合 Collection 內的成員 Member 的記憶體回收 Memory Garbage Collection 測試

在這個筆記中,我們將進一步的訓練大家關於記憶體回收的處理相關的觀念;在這裡,我們客製一個類別,MyTargetClass,這個類別內,僅有一個屬性,那就是我們客製類別 MyListClass,這個類別繼承了 List,所以,這個類別提供了一個集合的功能。
而在這個 MyListClass 是一個集合類別,他的每個成員為 MyClass 型別所產生的執行個體,這個類別僅有一個屬性 Name,用來標示每個物件的名稱。我們會在這個類別 MyClass 的建構函式與解構函式中,輸出一段訊息,說明現在是哪個物件被生成了,哪個物件被回收了。
    public class MyClass
    {
        public string Name { get; set; }
        public MyClass(string name)
        {
            Name = name;
            Console.WriteLine($"MyClass 型別建立一個物件 {Name}");
        }
        ~MyClass()
        {
            Console.WriteLine($"MyClass 型別的物件 {Name} 要被回收了");
        }
    }

    public class MyListClass : List<MyClass>
    {
        public MyListClass() : base()
        {
            Console.WriteLine($"MyListClass 型別建立一個物件");
        }
        ~MyListClass()
        {
            Console.WriteLine($"MyListClass 型別的物件 要被回收了");
        }
    }

    public class MyTargetClass
    {
        public MyListClass MyTargetClassObject { get; set; } = new MyListClass();
        public MyTargetClass()
        {
            Console.WriteLine($"MyTargetClass 型別建立一個物件");
        }
        ~MyTargetClass()
        {
            Console.WriteLine($"MyTargetClass 型別的物件 要被回收了");
        }
    }

進行測試

我們透過底下程式碼來進行建立出我們要測試的相關物件。
  • 首先,建立一個 MyTargetClass 類別物件 fooMyTargetClass
  • 接著,在這個物件變數的屬性 MyTargetClassObject,加入三個 MyClass 類別的物件
            Console.WriteLine("建立型別 MyTargetClass 的執行個體");
            MyTargetClass fooMyTargetClass = new MyTargetClass();
            Console.WriteLine("加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內");
            fooMyTargetClass.MyTargetClassObject.Add(new MyClass("集合物件1"));
            Console.WriteLine("加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內");
            fooMyTargetClass.MyTargetClassObject.Add(new MyClass("集合物件2"));
            Console.WriteLine("加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內");
            fooMyTargetClass.MyTargetClassObject.Add(new MyClass("集合物件3"));
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();
你可以從底下的訊息,得知到各個類別產生的物件順序與過程。
大部分的人,應該都可以知道這樣的執行結果。
建立型別 MyTargetClass 的執行個體
MyListClass 型別建立一個物件
MyTargetClass 型別建立一個物件
加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內
MyClass 型別建立一個物件 集合物件1
加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內
MyClass 型別建立一個物件 集合物件2
加入型別 MyClass 的執行個體到 MyTargetClassObject 集合內
MyClass 型別建立一個物件 集合物件3
接著,我們要將 fooMyTargetClass 這個物件變數的參考值,設定為空值,也就是剛剛生成的 MyTargetClass 類別的執行個體,在記憶體中,已經變成沒有任何變數有參考的到這個物件。
+

然後,我們就強制持行記憶體回收行程,我們執行 GC.Collect(); 這個敘述,完成這樣的需求。
這是我們使用的測試程式碼
            Console.WriteLine("將參考變數 fooMyTargetClass 設定為空值");
            fooMyTargetClass = null;
            Console.WriteLine("進行記憶體回收行程 Garbage Collection");
            GC.Collect();
            Console.WriteLine("休息3秒鐘");
            Thread.Sleep(3000);
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();
此時,根據上述的測試程式碼,就會得到底下的執行結果。您可以解釋出來,為什麼會得到這樣的結果嗎?
將參考變數 fooMyTargetClass 設定為空值
進行記憶體回收行程 Garbage Collection
休息3秒鐘
MyClass 型別的物件 集合物件3 要被回收了
MyClass 型別的物件 集合物件2 要被回收了
MyClass 型別的物件 集合物件1 要被回收了
MyListClass 型別的物件 要被回收了
MyTargetClass 型別的物件 要被回收了

沒有留言:

張貼留言