1. 程式人生 > 其它 >Java虛擬機器(JVM)面試題(2022最新版)

Java虛擬機器(JVM)面試題(2022最新版)

Java虛擬機器(JVM)面試題(2022最新版)

深拷貝和淺拷貝

淺拷貝(shallowCopy)只是增加了一個指標指向已存在的記憶體地址,
深拷貝(deepCopy)是增加了一個指標並且申請了一個新的記憶體,使這個增加的指標指向這個新的記憶體,
使用深拷貝的情況下,釋放記憶體的時候不會因為出現淺拷貝時釋放同一個記憶體的錯誤。
淺複製:僅僅是指向被複制的記憶體地址,如果原地址發生改變,那麼淺複製出來的物件也會相應的改變。
深複製:在計算機中開闢一塊新的記憶體地址用於存放複製的物件。

簡述Java垃圾回收機制

在java中,程式設計師是不需要顯示的去釋放一個物件的記憶體的,而是由虛擬機器自行執行。在JVM中,有一個垃圾回收執行緒,它是低優先順序的,在正常情況下是不會執行的,只有在虛擬機器空閒或者當前堆記憶體不足時,才會觸發執行,掃面那些沒有被任何引用的物件,並將它們新增到要回收的集合中,進行回收。

GC是什麼?為什麼要GC

GC 是垃圾收集的意思(Gabage Collection),記憶體處理是程式設計人員容易出現問題的地方,忘記或者錯誤的記憶體
回收會導致程式或系統的不穩定甚至崩潰,Java 提供的 GC 功能可以自動監測物件是否超過作用域從而達到自動
回收記憶體的目的,Java 語言沒有提供釋放已分配記憶體的顯示操作方法

垃圾回收的優點和原理。並考慮2種回收機制

java語言最顯著的特點就是引入了垃圾回收機制,它使java程式設計師在編寫程式時不再考慮記憶體管理的問題。
由於有這個垃圾回收機制,java中的物件不再有“作用域”的概念,只有引用的物件才有“作用域”。
垃圾回收機制有效的防止了記憶體洩露,可以有效的使用可使用的記憶體。
垃圾回收器通常作為一個單獨的低級別的執行緒執行,在不可預知的情況下對記憶體堆中已經死亡的或很長時間沒有用過的物件進行清除和回收。
程式設計師不能實時的對某個物件或所有物件呼叫垃圾回收器進行垃圾回收。
垃圾回收有分代複製垃圾回收、標記垃圾回收、增量垃圾回收。

垃圾回收器的基本原理是什麼?垃圾回收器可以馬上回收記憶體嗎?有什麼辦法主動通知虛擬機器進行垃圾回收?

對於GC來說,當程式設計師建立物件時,GC就開始監控這個物件的地址、大小以及使用情況。
通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件。通過這種方式確定哪些物件是"可達的",哪些物件是"不可達的"。當GC確定一些物件為"不可達"時,GC就有責任回收這些記憶體空間。
可以。程式設計師可以手動執行System.gc(),通知GC執行,但是Java語言規範並不保證GC一定會執行。

怎麼判斷物件是否可以被回收?

垃圾收集器在做垃圾回收的時候,首先需要判定的就是哪些記憶體是需要被回收的,哪些物件是「存活」的,是不可以被回收的;哪些物件已經「死掉」了,需要被回收。
一般有兩種方法來判斷:
引用計數器法:為每個物件建立一個引用計數,有物件引用時計數器 +1,引用被釋放時計數 -1,當計數器為 0 時就可以被回收。它有一個缺點不能解決迴圈引用的問題;
可達性分析演算法:從 GC Roots 開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到 GC Roots 沒有任何引用鏈相連時,則證明此物件是可以被回收的。

物件什麼時候可以被垃圾回收

當物件對當前使用這個物件的應用程式變得不可觸及的時候,這個物件就可以被回收了。
垃圾回收不會發生在永久代,如果永久代滿了或者是超過了臨界值,會觸發完全垃圾回收(Full GC)。如果你仔細檢視垃圾收集器的輸出資訊,就會發現永久代也是被回收的。這就是為什麼正確的永久代大小對避免Full GC是非常重要的原因。

JVM中的永久代中會發生垃圾回收嗎

 如果永久代滿了或者是超過了臨界值,會觸發完全垃圾回收(Full GC)。

說一下 JVM 有哪些垃圾回收演算法?

標記-清除演算法
標記-清除演算法:標記無用物件,然後進行清除回收。缺點:效率不高,無法清除垃圾碎片。
複製演算法:按照容量劃分二個大小相等的記憶體區域,當一塊用完的時候將活著的物件複製到另一塊上,然後再把已使用的記憶體空間一次清理掉。缺點:記憶體使用率不高,只有原來的一半。
標記-整理演算法:標記無用物件,讓所有存活的物件都向一端移動,然後直接清除掉端邊界以外的記憶體。
分代演算法:根據物件存活週期的不同將記憶體劃分為幾塊,一般是新生代和老年代,新生代基本採用複製演算法,老年代採用標記整理演算法。
標記-清除演算法
標記無用物件,然後進行清除回收。
標記-清除演算法(Mark-Sweep)是一種常見的基礎垃圾收集演算法,它將垃圾收集分為兩個階段:
標記階段:標記出可以回收的物件。
清除階段:回收被標記的物件所佔用的空間。
標記-清除演算法之所以是基礎的,是因為後面講到的垃圾收集演算法都是在此演算法的基礎上進行改進的。

優點:實現簡單,不需要物件進行移動。

缺點:標記、清除過程效率低,產生大量不連續的記憶體碎片,提高了垃圾回收的頻率。
複製演算法
為了解決標記-清除演算法的效率不高的問題,產生了複製演算法。它把記憶體空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾收集時,遍歷當前使用的區域,把存活物件複製到另外一個區域中,最後將當前使用的區域的可回收的物件進行回收。
優點:按順序分配記憶體即可,實現簡單、執行高效,不用考慮記憶體碎片。
缺點:可用的記憶體大小縮小為原來的一半,物件存活率高時會頻繁進行復制。
標記-整理演算法
在新生代中可以使用複製演算法,但是在老年代就不能選擇複製演算法了,因為老年代的物件存活率會較高,這樣會有較多的複製操作,導致效率變低。標記-清除演算法可以應用在老年代中,但是它效率不高,在記憶體回收後容易產生大量記憶體碎片。因此就出現了一種標記-整理演算法(Mark-Compact)演算法,與標記-整理演算法不同的是,在標記可回收的物件後將所有存活的物件壓縮到記憶體的一端,使他們緊湊的排列在一起,然後對端邊界以外的記憶體進行回收。回收後,已用和未用的記憶體都各自一邊。
優點:解決了標記-清理演算法存在的記憶體碎片問題。
缺點:仍需要進行區域性物件移動,一定程度上降低了效率。
分代收集演算法
當前商業虛擬機器都採用分代收集的垃圾收集演算法。分代收集演算法,顧名思義是根據物件的存活週期將記憶體劃分為幾塊。一般包括年輕代、老年代 和 永久代

說一下 JVM 有哪些垃圾回收器?

Serial收集器(複製演算法): 新生代單執行緒收集器,標記和清理都是單執行緒,優點是簡單高效;
ParNew收集器 (複製演算法): 新生代收並行集器,實際上是Serial收集器的多執行緒版本,在多核CPU環境下有著比Serial更好的表現;
Parallel Scavenge收集器 (複製演算法): 新生代並行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 使用者執行緒時間/(使用者執行緒時間+GC執行緒時間),高吞吐量可以高效率的利用CPU時間,儘快完成程式的運算任務,適合後臺應用等對互動相應要求不高的場景;

Serial Old收集器 (標記-整理演算法): 老年代單執行緒收集器,Serial收集器的老年代版本;
Parallel Old收集器 (標記-整理演算法): 老年代並行收集器,吞吐量優先,Parallel Scavenge收集器的老年代版本;
    
CMS(Concurrent Mark Sweep)收集器(標記-清除演算法): 老年代並行收集器,以獲取最短回收停頓時間為目標的收集器,具有高併發、低停頓的特點,追求最短GC回收停頓時間。
    
G1(Garbage First)收集器 (標記-整理演算法): Java堆並行收集器,G1收集器是JDK1.7提供的一個新收集器,G1收集器基於“標記-整理”演算法實現,也就是說不會產生記憶體碎片。此外,G1收集器不同於之前的收集器的一個重要特點是:G1回收的範圍是整個Java堆(包括新生代,老年代),而前六種收集器回收的範圍僅限於新生代或老年代。


詳細介紹一下 CMS 垃圾回收器?

是以犧牲吞吐量為代價來獲得最短回收停頓時間的垃圾回收器。對於要求伺服器響應速度的應用上,這種垃圾回收器非常適合。在啟動 JVM 的引數加上“-XX:+UseConcMarkSweepGC”來指定使用 CMS 垃圾回收器。
CMS 使用的是標記-清除的演算法實現的,所以在 gc 的時候回產生大量的記憶體碎片,當剩餘記憶體不能滿足程式執行要求時,系統將會出現 Concurrent Mode Failure,臨時 CMS 會採用 Serial Old 回收器進行垃圾清除,此時的效能將會被降低。

簡述分代垃圾回收器是怎麼工作的?

分代回收器有兩個分割槽:老生代和新生代,新生代預設的空間佔比總空間的 1/3,老生代的預設佔比是 2/3。

新生代使用的是複製演算法,新生代裡有 3 個分割槽:Eden、To Survivor、From Survivor,它們的預設佔比是 8:1:1,它的執行流程如下:

把 Eden + From Survivor 存活的物件放入 To Survivor 區;
清空 Eden 和 From Survivor 分割槽;
From Survivor 和 To Survivor 分割槽交換,From Survivor 變 To Survivor,To Survivor 變 From Survivor。
每次在 From Survivor 到 To Survivor 移動時都存活的物件,年齡就 +1,當年齡到達 15(預設配置是 15)時,升級為老生代。大物件也會直接進入老生代。

老生代當空間佔用到達某個值之後就會觸發全域性垃圾收回,一般使用標記整理的執行演算法。以上這些迴圈往復就構成了整個分代垃圾回收的整體執行流程。