每日三道面試題,通往自由的道路5——JVM

茫茫人海千千萬萬,感謝這一秒你看到這裏。但願個人面試題系列能對你的有所幫助!共勉!java

願你在將來的日子,保持熱愛,奔赴山海!面試

每日三道面試題,成就更好自我

昨天既然咱們聊到了JVM,那咱們繼續這一個話題吧!算法

1. JVM是如何判斷對象是否可回收

垃圾收集器在作垃圾回收的時候,首先須要判斷一個對象是存活狀態仍是死亡狀態,死亡的對象將會被標識爲垃圾數據並等待收集器進行清除。微信

而判斷一個對象是否爲可回收狀態的經常使用算法有兩個:引用計數器法和可達性分析算法。多線程

  • 引用計數器法:併發

    在 Java 中,引用和對象是有關聯的,經過引用計數來判斷一個對象是否能夠回收。它在建立對象時關聯一個與之相對應的計數器,當此對象被使用時加 1,相反銷燬時 -1。當此計數器爲 0 時,則表示此對象未使用,能夠被垃圾收集器回收。其優勢是垃圾回收比較及時,實時性比較高,只要對象計數器爲 0,則能夠直接進行回收操做;而缺點是沒法解決循環引用的問題。ide

  • 可達性分析算法:線程

    主要是從GC Root的對象爲起點出發,而後開始向下搜索,搜索走過的路徑稱爲引用鏈,當一個對象到GC Root之間沒有任何引用鏈的時候,表明這個對象不能夠用,判斷爲垃圾,就會被GC回收。對象

    在 java 中能夠做爲 GC Roots 的對象有如下幾種:blog

    • 虛擬機棧中引用的對象
    • 方法區類靜態屬性引用的對象
    • 方法區常量池引用的對象
    • 本地方法棧 JNI 引用的對象

不錯不錯,既然你能知道了如何判斷回收,那麼

2. 你知道有什麼垃圾回收的常見算法嗎?

  • 標記清除法:

    分爲標記--清除兩個階段,首先先標記出全部須要回收的對象,而後在標記完成後統一清除回收全部被標記的對象。

    它可能產生的問題呢標記清除後,產生一些大量不連續的內存碎片,致使可能之後後續的大內存找不到足夠的連續內存再致使提早又發生一次垃圾收集

  • 標記整理法:

    基本步驟和標記清除相似,可是多了一步整理的步驟,讓全部村後的對象都向一端移動,而後清除掉不須要的內存。

    它解決了內存碎片的問題,可是須要頻繁的移動存活的對象,效率就比較低了。

  • 複製算法:

    將可用的內存分爲一半,每次只使用一個區域。將須要存活的對象複製到另外一個對象中去。

    這種方法也是能夠解決了內存碎片問題,可是內存對半分了,並且對象存活率高的對象須要頻繁複制。

基於前面的算法的話,JVM採用一個分代算法的形式:

對於JVM的堆來講分爲了新生代和老年代兩個區域,而新生代也還分了eden區和兩個倖存區,他們比例是8:1:1,

對於新生代來講採用了複製算法,由於對於新生代來講每次垃圾回收的存活的對象是比較少的,因此採用複製算法較好,而老年代的話,則採用了標記整理法。

  • 首先對象會先分配在eden區,
  • 而後再新生代空間不足時,會發生一次minor gc算法將存活的對象複製到倖存區s1中,並使存活的對象的年齡加1,而後s1和s0交換,。
  • 在對象壽命超過閾值最大15時,就會晉升至老年代。
  • 而當老年代的空間不足時,會先嚐試觸發一次minor gc,若是空間仍是不足的話。就會出發full gc ,而此時的stw會更長。

能夠,那問你最後一道:

3. 你知道有什麼垃圾收集器嗎?

常見的垃圾收集器有:其中用於回收新生代的收集器有Serial、PraNew、Parallel Scavenge,而回收老年代的收集器有Serial Old、Parallel Old、CMS,最後還有一個能夠用於回收整個Java堆的G1收集器。

做用於新生代的:

  • Serial 收集器屬於最先期的垃圾收集器,也是 JDK 1.3 版本以前惟一的垃圾收集器。它是單線程的垃圾收集器,採用複製算法,其意味着單線程是指在進行垃圾回收時全部的工做線程必須暫停,直到垃圾回收結束爲止。

    特色是簡單和高效,而且自己的運行對內存要求不高,所以它在客戶端模式下使用的比較多。

  • sParNew 收集器其實是 Serial 收集器的多線程並行版本,也是採用複製算法。

  • Parallel Scavenge 收集器和 ParNew 收集器相似,它也是一個並行運行的垃圾回收器;不一樣的點在於該收集器關注的側重點是實現一個能夠控制的吞吐量。它的計算公式是:用戶運行代碼的時間 / (用戶運行代碼的時間 + 垃圾收集的時間)。好比用戶運行的時間是 8 分鐘,垃圾回收運行的時間是 2 分鐘,那麼吞吐量就是 80%。Parallel Scavenge 收集器追目標就是達到一個可控制的吞吐量,高吞吐量能夠最高效率地利用CPU時候,儘快地完成程序的運算任務。

做用於老年代的:

  • Serial Old 收集器爲 Serial 收集器的老年代版本,而 Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本。二者都是在老年代中採用這標記—— 整理算法。

  • CMS(Concurrent Mark Sweep)以獲取最短回收停頓時間爲目標,與Parallel Scavenge 收集器不一樣,是基於標記 —— 清除算法實現。它強調的是提供最短的停頓時間,所以可能會犧牲必定的吞吐量。它主要應用在 Java Web 項目中,它知足了系統須要短期停頓的要求,以此來提升用戶的交互體驗。CMS 工做機制相比其餘的垃圾收集器來講更復雜。整個過程分爲如下 4 個階段:

    • 初始標記(CMS initial mark):標記 GC Roots 能直接關聯到的對象
    • 併發標記(CMS concurrent mark):進行 GC Roots Tracing
    • 從新標記(CMS remark):修正併發標記期間的變更部分
    • 併發清除(CMS concurrent sweep):清除 GC Roots 不可達對象,和用戶線程一塊兒工做,不須要暫停工做線程。

做用於整個Java堆包括新生代和老年代的。

  • Garbage First(簡稱 G1)收集器是歷史發展的產物,也是一款更先進的垃圾收集器,主要面向服務端應用的垃圾收集器,是基於基於標記-整理算法實現,不產生內存碎片。它將內存劃分爲多個 Region 分區,回收時則以分區爲單位進行回收,這樣它就能夠用相對較少的時間優先回收包含垃圾最多區塊。此外,G1收集器不一樣於以前的收集器的一個重要特色是:G1回收的範圍是整個Java堆(包括新生代,老年代),而前六種收集器回收的範圍僅限於新生代或老年代。從 JDK 9 以後也成了官方默認的垃圾收集器,官方也推薦使用 G1 來代替選擇 CMS 收集器。

小夥子不錯嘛!今天就到這裏,期待你明天的到來,但願能讓我繼續保持驚喜!

注: 若是文章有任何錯誤和建議,請各位大佬盡情留言!若是這篇文章對你也有所幫助,但願可愛親切的您給個三連關注下,很是感謝啦!也能夠微信搜索太子爺哪吒公衆號私聊我,感謝各位大佬!

相關文章
相關標籤/搜索