程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 弱引用應用的注意點

弱引用應用的注意點

編輯:C#入門知識

1.弱引用的基礎介紹

    在某些場合,例如緩存某些大數據對象的時候,會遇到內存與時間的兩難境況,如果讓大對象過快的過期,那麼每次創建對象會消耗過多的性能,反之,保持了過多的大對象,那麼內存將耗盡,反而降低速度。

    此時,.net BCL中的弱引用(WeakReference)就出場了,如果內存尚且足夠,那麼GC就不會回收大對象占用的內存,那麼弱引用就是可到達的,也就是說可以重用這個對象,達到緩存的目的。如果內存不足,那麼GC就會不得不去回收那些大對象,從而釋放內存空間。

    當然,要釋放這些大對象的前提是沒有任何可到達的引用(之後將成其為強引用,以強調與弱引用的區別)。換而言之,就是弱引用本身並不影響GC回收對象。

2.引出問題

    來看看這段程序:

        static void Main(string[] args)
        {
            WeakReference wr = GetWR();
            while (wr.IsAlive)
            {
                Thread.Sleep(100);
            }
            Console.WriteLine("OK");
            Console.ReadLine();
        }

        private static WeakReference GetWR()
        {
            object o = new object();
            WeakReference wr = new WeakReference(o);
            return wr;
        }

    看起來像那麼回事,通過GetWR方法,獲得了一個對象的弱引用,退出方法後,那麼對這個對象的所有強引用就沒了,理論上,wr.IsAlive將在某個時間變成false,也就是對象被GC回收了。但是運行起來,卻發現,根本不會打出“OK”,為啥?因為沒有新的對象被創建出來,GC一直認為不需要回收,然後,就一直是一個看起來不是死循環的死循環了,直到哪天GC大發慈悲,回收一把。

    那麼這段代碼怎麼修改才能正確執行哪?不就是GC不肯回收嘛,強制回收就可以了,最簡單的就是加上一句GC.Collect(),這樣這個循環就能在適當的時候退出了。

3.弊端

    前面通過GC.Collect()方法解決了死循環問題,不過,又牽涉到另一個問題:GC.Collect()本身是一個比較消耗的操作,如果每0.1秒來一次全代回收,小程序是不要緊,但是服務類的程序可就不行了,這個性能會被拖慢,而且,全回收也會破壞那些企望盡量長時間停留在內存的大對象的駐留(也就是一開始說的正確的運用方式),因此弊端也不小。因此,在使用弱引用應該盡量避免這類應用:

  • 在前台線程使用循環並且退出條件是某弱引用不可到達

    如果使用這種方式,那麼在整個應用程序結束時,需要所有的前台線程完成,而如果其中的一個前台線程出現了類似while(wr.IsAlive)的代碼,就需要等待GC將被弱引用的對象回收,然而,GC的回收通常是不受控制的(可能很快,也可能需要很久),也就是說,這個前台線程可能會存活相當長的時間,並且由於是前台線程,以至於進程也會存活這樣長的時間(對於用戶而言,就是程序關不掉)。

 

PS:用了好久Paste As VS Code插件,今天終於發現了一個弊端,Host OS(win2003)上的VS中復制的代碼無法用這個插件貼到Guest OS(win 7 in Virtual Box)上,當然這個也不能算缺陷,只能說是虛擬機應用上的一個小小的遺憾吧。

    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved