2017年9月4日 星期一

.NET C# 物件參考與弱式參考的比較

在 C# 程式設計中,只要物件又被任何一個或以上的物件變數參考到的時候,並且記憶體回收機制被觸發執行的時候,這些物件是不被回收的。
若此時,我們採用了弱勢參考方式,則這些物件就會被記憶體機制回收。
底下為這次的測試專案原始碼:

範例原始碼

    public class MyClass
    {
        public string Name { get; set; }
        public MyClass(string name)
        {
            Name = name;
            Console.WriteLine($"----------> MyClass類別產生一個物件 : {Name}");
        }
        ~MyClass()
        {
            Console.WriteLine($"==========> MyClass類別的一個物件被記憶體回收了 : {Name}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 正常參考一個物件,只要該參考持續存在,該物件就不會被記憶體回收
            MyClass strongReference = new MyClass("Strong Reference Object") ;
            // 表示弱式參考,即在參考物件的同時,仍允許系統透過記憶體回收來回收該物件。
            WeakReference weakReference = new WeakReference(new MyClass("Weak Reference Object"));

            Console.WriteLine($"正常使用的參考物件為 {strongReference.Name}");
            Console.WriteLine($"弱式參考物件是否還存在 {weakReference.IsAlive}");
            Console.WriteLine($"弱式參考物件為 {(weakReference.Target as MyClass).Name}");
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();

            Console.WriteLine("強制進行記憶體回收,等候三秒鐘...");
            GC.Collect(2);
            Thread.Sleep(3000);


            Console.WriteLine($"正常使用的參考物件為 {strongReference.Name}");
            Console.WriteLine($"弱式參考物件是否還存在 {weakReference.IsAlive}");
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();

            ReAccessWeakReference(strongReference, weakReference);

            Console.WriteLine($"正常使用的參考物件為 {strongReference.Name}");
            Console.WriteLine($"弱式參考物件是否還存在 {weakReference.IsAlive}");
            Console.WriteLine($"弱式參考物件為 {(weakReference.Target as MyClass).Name}");
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();
        }

        static void ReAccessWeakReference(MyClass strongReference, WeakReference weakReference)
        {
            if (weakReference.Target == null)
            {
                Console.WriteLine("因為弱式參考的物件不存在了,所以重新取得該弱式參考物件...");
                weakReference.Target = new MyClass("再次產生的 Weak Reference Object");
            }

        }
    }

程式執行結果

----------> MyClass類別產生一個物件 : Strong Reference Object
----------> MyClass類別產生一個物件 : Weak Reference Object
正常使用的參考物件為 Strong Reference Object
弱式參考物件是否還存在 True
弱式參考物件為 Weak Reference Object
Press any key for continuing...
強制進行記憶體回收,等候三秒鐘...
==========> MyClass類別的一個物件被記憶體回收了 : Weak Reference Object
正常使用的參考物件為 Strong Reference Object
弱式參考物件是否還存在 False
Press any key for continuing...
因為弱式參考的物件不存在了,所以重新取得該弱式參考物件...
----------> MyClass類別產生一個物件 : 再次產生的 Weak Reference Object
正常使用的參考物件為 Strong Reference Object
弱式參考物件是否還存在 True
弱式參考物件為 再次產生的 Weak Reference Object
Press any key for continuing...

程式運行說明

首先,我們定義一個非常簡單的類別,在這個類別,我們建立一個有參數的建構式,用來建立該物件之用,當該物件被建立的時候,會在控制台中顯示該物件已經產生的訊息;另外,我們也建立解構函式,當該物件被記憶體回收的時候,也會在控制台中顯示該物件已經被回收的訊息。
+

在程式一開始執行的時候,我們建立兩個物件,一個是一般參考的物件,一個為弱式參考物件。
然後,我們確認這兩個物件都存在於系統中,也就是我們可以透過程式來進行存取這兩個物件。
            // 正常參考一個物件,只要該參考持續存在,該物件就不會被記憶體回收
            MyClass strongReference = new MyClass("Strong Reference Object") ;
            // 表示弱式參考,即在參考物件的同時,仍允許系統透過記憶體回收來回收該物件。
            WeakReference weakReference = new WeakReference(new MyClass("Weak Reference Object"));
接著,我們強制執行記憶體回收機制,並且要等候三秒鐘(這是要讓背景記憶體回收工作可以順利完成,因為是在背景執行緒中運行,我們並無法可以確實掌握到這樣的執行工作何時可以完成。
之後,我們確認屬性 IsAlive 是否為 false,這表示該弱式參考的物件已經不存在於系統上(也就是被回收了)。
若我們這個時候想要繼續使用這個物件,我們可以使用敘述 weakReference.Target == null 確認物件是否還存在,若沒有,我們就可以再度產生該物件,這樣,我們還是可以繼續透過弱式參考的方式,存取該物件。
最後,我們可以從控制台畫面中,看到建立物件與回收物件行為發生的時候的訊息,這樣,我們便可以得到這些測試物件是有備確實建立與回收。

沒有留言:

張貼留言