-
1 # 教女朋友學程式設計
-
2 # 瞥瞥張
引用計數演算法
給物件新增一個引用計數器,每當一個地方引用它時,資料器加1;當引用失效時,計數器減1;計數器為0的即可被回收。
優點:實現簡單,判斷效率高缺點:很難解決物件之間的相互迴圈引用(objA.instance = objB; objB.instance = objA)的問題,所以java語言並沒有選用引用計數法管理記憶體根搜尋演算法Java和C#都是使用根搜尋演算法來判斷物件是否存活。透過一系列的名為“GC Root”的物件作為起始點,從這些節點開始向下搜尋,搜尋所有走過的路徑稱為引用鏈(Reference Chain),當一個物件到GC Root沒有任何引用鏈相連時(用圖論來說就是GC Root到這個物件不可達時),證明該物件是可以被回收的。
在Java中這些物件可以成為GC Root:
虛擬機器棧(棧幀中的本地變量表)中的引用物件
方法區中的類靜態屬性引用的物件
方法區中的常量引用物件
本地方法棧中JNI(即Native方法)的引用物件
標記-清除演算法標記-清除演算法是一種常見的基礎垃圾收集演算法,它將垃圾收集分為兩個階段
標記階段:標記出可以回收的物件。
清除階段:回收被標記的物件所佔用的空間。
標記-清除演算法主要有兩個缺點,一個是標記和清除的效率不高,另一個從圖中就可以看出,就是容易產生大量不連續的記憶體碎片,碎片太多可能會導致後續沒有足夠的連續記憶體分配給較大的物件,從而提前觸發新的一次垃圾收集動作。
複製演算法為了解決標記-清除演算法的效率不高的問題,產生了複製演算法。它把記憶體空間劃分為兩個相等的區域,每次只使用其中一個區域。在垃圾收集時,遍歷當前使用的區域,把存活物件複製到另一個區域中,最後將當前使用的區域的可回收的物件進行回收。
這種演算法每次都對整個半區進行記憶體回收,不需要考慮記憶體碎片的問題,代價就是使用記憶體為原來的一半。複製演算法的效率與存活物件的數目多少有很大的關係,如果存活物件很少,複製演算法的效率就會很高。由於絕大多數物件的生命週期很短,並且這些生命週期很短的物件都存於新生代中,所以複製演算法被廣泛應用於新生代中。
標記-壓縮演算法在新生代中可以使用複製演算法,但是在老年代就不能選擇複製演算法,因為老年代物件存活率會較高,這樣會有較多的複製操作,導致效率變低。標記-清除演算法可以應用在老年代中,但是效率不高,在記憶體回收後容易產生大量記憶體碎片。因此就出現了一種標記-壓縮演算法,與標記-清除演算法不同的是,在標記可回收的物件後將所有存活的物件壓縮到記憶體的一端,使它們緊湊地排列在一起,然後對邊界以外的記憶體進行回收,回收後,已用和未用的記憶體都各自一邊。
標記-壓縮演算法解決了標記-清除演算法效率低和容易產生大量記憶體碎片的問題,它被廣泛應用於老年代中。
分代收集演算法分代收集演算法會結合不同的收集演算法來處理不同的空間,因此在學習分代收集演算法之前我們首先要了解Java堆區的空間劃分。Java堆區的空間劃分在Java虛擬機器中,各種物件的生命週期會有著較大的差別,大部分物件生命週期很短暫,少部分物件生命週期很長,有的甚至與應用程式以及Java虛擬機器的執行週期一樣長。因此,應該對不同生命週期的物件採取不同的收集策略,根據生命週期長短將它們放到不同的區域,並在不同的區域採用不同的收集演算法,這就是分代的概念。現在主流的Java虛擬機器的垃圾收集器都採用分代收集演算法。Java堆區基於分代的概念,分為新生代和老年代,其中新生代再細分為Eden空間、From Survivor空間和To Survivor空間。因為Eden空間中的大多數生命週期很短,所以新生代的空間劃分並不是均分的,HotSpot虛擬機器預設Eden空間和兩個Survivor空間的所佔的比例為8:1。
根據Java堆區的空間劃分,垃圾收集的型別分為兩種,它們分別如下:
Minor Collection:新生代垃圾收集。
Full Collection:對老年代進行收集,又可以稱作Major Collection,Full Collection通常情況下會伴隨至少一次的Minor Collection,它的收集頻率較低,耗時較長。
當執行一次Minor Collection時,Eden空間的存活物件會被複制到To Survivor空間,並且之前經過一次Minor Collection 並在From Survivor空間存活的仍年輕的物件也會複製到To Survivor空間。有兩種情況Eden空間和From Survivor空間存活的物件不會複製到To Survivor空間, 而是晉升到老年代。一種是存活的物件的分代年齡超過-XX:MaxTenuringThreshold(用於控制物件經歷多少次Minor GC 才晉升到老年代)所指定的閾值。另一種是To Survivor空間容量達到閾值。當所有存活的物件被複制到To Survivor空間,或者晉升到老年代,也就意味著Eden空間和From Survivor空間剩下的都是可回收物件。
這個時候GC執行Minor Collection,Eden空間和From Survivor空間都會被清空,新生代存活的物件都存放在To Survivor空間。接下來將From Survivor空間和To Survivor空間互換位置,也就是此前的From Survivor空間成為了現在的To Survivor空間,每次Survivor空間互換都要保證To Survivor空間是空的,這就是複製演算法在新生代中的應用。在老年代則會採用標記-壓縮演算法或標記-清除演算法。
回覆列表
垃圾回收 讓程式設計師把精力放在了 業務邏輯上,而不是記憶體管理上!
缺點是 讓程式設計師更傻了,對底層更加不瞭解!