垃圾回收問題
垃圾回收算法
通過之前的學習我們可以將死亡對象標記出來了,標記出來后我們就可以進行垃圾回收操作了,在正式學習垃圾處理器之前,我們先來看一下垃圾回收器使用的幾種算法.
標記-清除算法
"標記-清除"算法是基礎的收集算法.算法分為"標記"和"清除"兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象.后續的收集算法都是基于這種思路加以改造并對其不足加以改進而已:
"標記-清除"算法的不足主要有兩個:
1.效率問題:標記和清除這兩個過程的效率都不高.2.空間問題:標記清除后會產生大量不連續的內存碎片,內存碎片太多可能會導致以后在程序運行中需要分配較大對象時,無法找到足夠連續內存而不得不提前觸發另一次垃圾收集.
?復制算法
?"復制算法是為了解決"標記-清理"的效率問題.它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊.當這塊內存需要進行垃圾回收時,會將此區域還存活著的對象復制到另一塊上面,然后再把已經使用過的內存區域一次清理掉.這樣做的好處是每次都對整個半區進行內存回收,內存分配時也就不需要考慮內存碎片等復雜的情況,只需要移動堆頂指針,按順序分配即可.此算法實現簡單,運行高效.算法的執行流程如下圖:
通過復制算法這種機制確實能在一定程度上規避內存問題,但也有一定缺陷.
1.總的可用內存,變少了.
2.如果每次要復制的對象比較多,此時復制的開銷比較大,需要的是當前一輪(當中,大部分對象被釋放,少數對象存活,在這個時候最適合復制).?
現在的商用虛擬機(包括HotSpot都是采用這種收集算法來回收新生代)
引入概念:對象的年齡.JVM有專門的線程負責掃描/釋放一個對象,如果被線程掃描的時候,可達了(不是垃圾), 年齡+1 =>在對象類中存儲年齡.
?新生代中98%的對象都是"朝生暮死"的,所以不需要按照1:1的比例來劃分內存空間,而是將內存(新生代內存)分為一塊較大的Eden(伊甸園)空間和兩塊較小的Survivor(幸存者空間),每次使用Eden和其中一塊Survivor(兩個Survivor區域一個稱為from區,另一個稱為To區).當回收時,將Eden和Survivor中還存活的對象一次性復制到另一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor的空間.
當Survivor空間不夠用的時候,需要依賴其它內存(老年代)機型分配擔保.
HotSpot默認Eden與Survivor的大小比例是8:1,也就是說:Eden : Survivor From : Survivor To = 8:1:1.所以每次新生代的可用空間為整個新生代容量的90%,而剩下的10%用來存放回收后存活的對象.
下面來看一下具體的算法執行流程:
(1)當代碼中new出一個對象,這個對象就是被創建在伊甸區的,伊甸區能有很多對象.一個經驗規律:伊甸區的對象都是"朝生暮死"的,生命周期非常短.
(2)第一輪GC掃描完成之后,少數伊甸區中幸存的對象就會通過算法拷貝到生存區,后續GC掃描線程還會持續進行掃描,不僅會掃描伊甸區,也會掃描生存區的對象,生存區中也有大量對象被標記為垃圾,少數存活的,就會使用算法,拷貝到另一個生存區中.只要這個能夠在生存區中繼續存活,就會被復制算法,拷貝到另一個生存區中,每經過一次GC掃描,對象年齡+1
(3) 如果該對象存儲在生存區中,經歷了若干輪GC依然健在,JVM就會認為,這個對象生命周期大概率會很長,就把這個對象從生存區拷貝到老年代.
(4)老年代對象,也會被GC掃描,但是掃描的頻次大大降低.
(5)當對象在老年代中壽終正寢的時候,JVM按標記整理的方式,進行清除.
標記-整理算法
復制收集算法在對象存活率較高時會進行比較多的復制操作,效率會變低.因此老年代一般不能使用復制算法.
針對老年代的特點,提出了一種稱之為"標記-整理算法".標記過程仍與"標記-清除"的過程一致,但后續的步驟不是直接對可回收對象進行整理,而是讓所有存活對象都向一端移動,然后清理掉邊界以外的內存.流程圖如下:
?分代算法
分代算法和上面講的三種算法不同,分代算法是通過區域的劃分,實現不同區域和不同的垃圾回收策略,從而實現更好的垃圾回收.就好比中國的一國兩制方針一樣,對于不同的情況和地域設置更符合當地的規則,從而實現更好的管理,這就是分代算法的設計思想.
當前JVM垃圾收集器采用的是"分代收集"算法,這個算法并沒有新思想,只是根據對象的存活周期的不同將內存劃分為幾塊.一般是把Java堆分為新生代和老年代.在新生代中,每次垃圾回收都有大批對象死去,只有少量存活,因此我們采用復制算法;而老年代中對象存活率高,沒有額外空間對它進行分配擔保,就必須采用"標記-清理"或者"標記-整理"算法.
哪些對象會進入新生代?哪些對象會進入老年代?
新生代:一般創建的對象都會進入新生代;
老年代:大對象經歷了N次(默認情況下是15次)垃圾回收依然存活下來的對象會從新生代移動到老年代.
面試問題:請問了解Minor GC和Full GC么,這兩種GC有什么不一樣嗎?
1.Minor GC又稱為新生代GC:指的是發生在新生代的垃圾收集.因為Java對象大多都具有朝生暮死的特性,因此Minor GC(采用復制算法)的使用非常頻繁,一般回收速度也比較快.
2.Full GC又稱為老年代GC或者Major GC:指發生在老年代的垃圾收集.出現了Major GC,經常會伴隨至少一次的Minor GC(并非絕對,在Parallel Scavenge收集器中就有直接進行Full GC的策略選擇過程).Major GC的速度一般會比Minor GC慢10倍以上.?