面試官超級喜歡問的垃圾回收算法
本文轉載自微信公眾號「程序員巴士」,作者七十一 。轉載本文請聯系程序員巴士公眾號。
前言
經過前段時間一面的通過,阿巴阿巴被邀請進入二面,這次她與遇到的面試官將繼續為難她,要問她關于GC算法的問題。
回家等通知
面試官: 你對JVM的垃圾回收了解嗎?
阿巴阿巴: 嗯嗯,了解一些。
面試官: 那么JVM是如何判斷一個對象是垃圾呢?
阿巴阿巴: 好像有一個可達性分析法。
阿巴阿巴: 就是對象可達會判定為活對象,然后不可達的就當作“垃圾”。
面試官: 嗯....講一下你了解的垃圾回收算法吧。
阿巴阿巴:
標記清楚算法
標記整理算法
復制算法
分代收集算法
面試官: 嗯....那你對這些算法了解嗎?
阿巴阿巴: 嗯....不太了解...
面試官: 行,今天先面到這里,你這邊先回去等通知吧??
阿巴阿巴: 好的。
很遺憾,您未能通過面試,您的簡歷已加入公司人才庫,期待下次相遇......
當場拿Offer
面試官: 你對JVM的垃圾回收了解嗎?
阿巴阿巴: 嗯嗯,了解一些。
面試官: 那么JVM是如何判斷一個對象是垃圾呢?
阿巴阿巴: 有兩種方法,一種是引用計數法,另一種是可達性分析法。
阿巴阿巴: 引用計數法就是給對象一個引用計數器,每當有引用引向該對象時,引用計數器就加一,每當有引用斷開的時候,引用計數器就減一,這樣當引用計數器為零時,那么就認為這個對象已經沒有用了,也就是所謂的“垃圾”,但是這種方式有個很大的弊端,對于循環引用無法處理。
阿巴阿巴: 循環引用的對象外部引用存在的情況,這種情況看似沒啥問題,但是當我們把方法區的引用斷開時,問題就暴露出來了。
阿巴阿巴: 循環引用的對象外部引用斷開的情況。
阿巴阿巴: 上面這種引用斷開的情況,顯然對象A和對象B已經沒有外部引用來引用它們,它們已經成為了垃圾,而引用計數器因為它們相互引用(循環引用),其值都為1,導致無法被回收,這個弊端導致引用計數法實際并沒有在JVM中所使用。
阿巴阿巴: 可達性分析法就是通過GC Roots的對象,以它為根往下搜索,這條被搜索的路徑稱為“引用鏈”,當一個對象不被任何GC Roots的引用鏈所鏈接,那么就判定這個對象已經“死了”,我們一般稱這個對象“不可達”。
面試官: 你剛有提到GC Roots,那你知道哪些對象可以作為GC Roots的對象嗎?
阿巴阿巴: 嗯嗯了解,主要有以下四類對象可以作為GC Roots的對象。
- 虛擬機棧中引用的對象
- 方法區中靜態屬性引用的對象
- 方法區中常量引用的對象
- 本地方法棧中引用的對象
阿巴阿巴: 下面這張圖可以直觀的看出它們的關系。
阿巴阿巴: 可以看出,只有被引用鏈鏈上的對象才能被判定為“存活”,而不在引用鏈上的對象則被判定為“死亡”,也將作為垃圾被回收。
面試官: 講的很不錯,那垃圾回收除了回收堆中的對象外,方法區中會有垃圾被回收嗎?
阿巴阿巴: 方法區中也是有垃圾回收的,方法區中主要回收廢棄了的常量和無用的類。
面試官: 嗯....講一下你了解的垃圾回收算法吧。
阿巴阿巴: 垃圾回收算法主要有以下四類。
- 標記清楚算法
- 標記整理算法
- 復制算法
- 分代收集算法
阿巴阿巴: 標記清楚算法,是分為2個階段的,第一個階段進行“標記”,第二個階段進行“清除”,先標記出所有要清除的對象,也就是灰色部分,然后進行回收。
阿巴阿巴: 采用標記清除算法對堆進行垃圾清理后,產生了很多空間碎片,這些空間碎片使新對象的內存分配造成困難,不僅如此,標記清除算法在標記階段和清除階段的效率都不太高。
阿巴阿巴: 標記整理算法孕育而生,解決了過多內存碎片的問題。
阿巴阿巴: 為了解決效率的問題,復制算法也出現了,即把一塊內存分成大小相等的2塊,每次使用的時候只使用其中的一塊,當一塊內存使用完的時候,把這塊內存中存活的對象轉移到另一塊內存中,然后將這塊內存中的對象全部清空。
阿巴阿巴: 復制算法實現簡單、方便且效率很高,也不需要考慮內存碎片的問題,但是要將內存縮小為原來的一半,這代價無疑很高。
阿巴阿巴: 而且新生代的對象大多數都是朝生夕死的,按照1:1的空間比例來使用復制算法,將極大的影響了內存的性能。
阿巴阿巴: 分代算法即將堆區進行劃分,然后根據不同區域的情況來適用相應的垃圾回收算法。
阿巴阿巴: 下圖是對新生代的細化,新生代分成Eden區和survivor區,其中survivor區又分為(s0和s1)倆個區域,它們的比例如圖所示為8 : 1 : 1。新對象優先會在Eden區進行分配,標記清除算法在這里不適用,因為碎片太多,如果沒有連續的足夠空間來分配給對象,又會繼續觸發垃圾回收,對性能影響比較大。
阿巴阿巴: 對于傳統的GC來說,都無法避免GC過程中帶來的“STOP-THE-WORLD”,我們一般簡稱STW,STW對系統性能的影響很大,那么如何消除STW或者減少STW的時間顯得尤為重要,其實分代算法并非是一種具體的算法,和前面的標記清除、標記整理算法、復制算法不同的是,分代算法只是對對堆得一個劃分,然后在不同區域使用不同的算法,從而將STW的時間細分到各個區域,使得STW時間不會持續很長一段時間,來達到提高系統性能的目的。
面試官: 講的很清楚細致了,很不錯,明天來上班吧??。
總結
關于垃圾回收算法這一塊,一定要答到GC Roots,以及各種垃圾回收算法,及他們的優點和缺點。