標籤:工作 font XML 引用計數器 strong c# 開始 reference .com
記憶體回收(Garbage Collection,GC ),GC的曆史其實比Java久遠,1960年誕生與MIT的Lisp是第一門真正使用記憶體動態分配和垃圾收集技術的語言。當Lisp還在胚胎時期時,人們就在思考GC需要完成的3件事情:
問:經過半個多世紀的發展,目前記憶體的動態分配與記憶體回收技術已經相當成熟,一切看起來都進入了“自動化”時代,為何我們還要去瞭解GC和記憶體配置呢?
答:當需要排查各種記憶體溢出、記憶體泄露問題時,當垃圾收整合為系統達到更高並發量的瓶頸時,我們就需要對這些“自動化”的技術實施必要的監控和調節。 確定GC回收的地區: (1)程式計數器、虛擬機器棧、本地方法棧這3個地區隨線程而生,隨線程而滅。每一個棧幀中分配多少記憶體基本上是在類結構確定下來時就已知的,因此這幾個地區的記憶體配置和回收都具備確定性,在這幾個地區內就不需要過多考慮回收的問題,因為方法結束或線程結束時,記憶體自然就跟著回收了。 (2)Java堆(Heap)和方法區則不一樣,一個介面中的多個實作類別需要的記憶體可能不一樣,一個方法中的多個分支需要的記憶體也可能不一樣,我們只有在程式處於運行期間時才能知道會建立哪些對象,這部分記憶體的分配和回收都是動態,垃圾收集器所關注的是這部分記憶體。 1.判斷對象是否存活的演算法之一:引用計數演算法。 演算法思想以及應用分析: (1)給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的。 (2)客觀地說,引用計數演算法的實現簡單,判定效率也很高,在大部分情況下都是一個不錯的演算法,也有一些著名的應用案例,例如微軟公司的COM(Component Object Model)技術、使用ActionScript 3的Flashplayer、Python語言和在遊戲指令碼領域被廣泛應用的Squirrel中都使用了引用計數演算法進行記憶體管理。 (3)但是主流的Java虛擬機器裡面沒有選用引用計數演算法來管理記憶體,其中最主要的原因是它很難解決對象之間相互循環參考的問題。 2.針對對象之間相互循環參考的問題進行的實驗如所示: 從上面的運行結果可以得到,GC日誌中包含的“8028K->512K”,意味著虛擬機器並沒有因為這兩個對象互相引用就不回收它們,這也從側面說明虛擬機器並不是通過引用計數演算法來判斷對象是否存活的。 3.判斷對象是否存活的演算法之一: 可達性分析演算法。 演算法思想及應用: (1)這個演算法基本思想就是通過一系列的成為“GC Roots”的對象作為起始點,從這些節點開始向下搜素,搜素所做過的路徑成為引用鏈(Reference Chain)。當一個對象到GC Roots沒有任何引用鏈相連(圖論中為從GC Root到這個對象不可達)時,則證明此對象是停用。如所示: (2)在Java語言中,可作為GC Roots的對象包括下面: a.虛擬機器棧(棧幀中的本地變數表)中引用的對象。
b.方法區中類靜態屬性引用的對象。
c.方法區中常量引用的對象。
d.本地方法棧中JNI(Native 方法)引用的方法。
(3)在主流的商用程式語言(Java、C#,甚至包括前面提到的古老的Lisp)的主流實現中,都是稱通過可達性分析(Reachability Analysis)來判定對象是否存活的。 4. 再談引用
引用的定義:在JDK 1.2以前,Java中的引用定義很傳統:如果reference類型的資料存放區的數值代表的是另外一塊記憶體的起始地址,就稱這塊記憶體代表著一個引用。
問題出現了:當描述這樣的一類對象:當記憶體空間還足夠時,則能保留在記憶體之中,如果記憶體空間在進行垃圾收集後還是非常緊張,則可以拋棄這些對象。此時的引用就顯得過於狹隘。因此在JDK 1.2之後,Java堆引用的概念進行了擴充。
| 強引用 |
Strong Reference |
類似Object obj = new Object() |
只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象 |
| 軟引用 |
Soft Reference |
描述一些還有用但並非必須的對象 |
在系統將要發生記憶體溢出的異常之前,將會把這些對象列進回收範圍之中進行第二次回收。如果這次回收還沒有足夠的記憶體,才會拋出記憶體溢出異常 |
| 弱引用 |
Wear Reference |
用來描述非必須對象,強度比軟引用更弱。被弱引用關聯的對象只能生存到下一次垃圾收集發生之前 |
當垃圾收集器工作時,無論當前記憶體是否足夠,都會回收掉紙杯弱引用關聯的對象 |
| 虛引用 |
Phantom Reference |
又稱為幽靈引用或幻影引用,最弱的一種參考關聯性。一個對象是否有虛引用的存在,完全不會對其存留時間構成影響,也無法通過虛引用來取得一個對象執行個體。 |
為一個對象設定虛引用關聯的衛衣目的就是能在這個對象被收集器回收時收到一個系統通知 |
深入理解 JAVA 虛擬機器之學習筆記(3)