前言
本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!說說堆和棧的區別?什麼時候會觸發FullGC?什麼是Java虛擬機器?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤
*** 12萬字的java面試題整理 ***
說說堆和棧的區別
棧是執行時單位,代表著邏輯,內含基本資料型別和堆中物件引用,所在區域連續,沒有碎片;堆是儲存單位,代表著資料,可被多個棧共享(包括成員中基本資料型別、引用和引用物件),所在區域不連續,會有碎片。
1. 功能不同
棧記憶體用來儲存區域性變數和方法呼叫,而堆記憶體用來儲存Java中的物件。無論是成員變數,區域性變數,還是類變數,它們指向的物件都儲存在堆記憶體中。
2. 共享性不同
棧記憶體是執行緒私有的。 堆記憶體是所有執行緒共有的。
3. 異常錯誤不同
如果棧記憶體或者堆記憶體不足都會丟擲異常。 棧空間不足:java.lang.StackOverFlowError。 堆空間
不足:java.lang.OutOfMemoryError。
4. 空間大小
棧的空間大小遠遠小於堆的。
什麼時候會觸發FullGC
除直接呼叫System.gc外,觸發Full GC執行的情況有如下四種。
1. 舊生代空間不足
舊生代空間只有在新生代物件轉入及建立為大物件、大陣列時才會出現不足的現象,當執行Full GC後空間仍然不足,則丟擲如下錯誤: java.lang.OutOfMemoryError: Java heap space 為避免以上兩種狀況引起的FullGC,調優時應儘量做到讓物件在Minor GC階段被回收、讓物件在新生代多存活一段時間及不要建立過大的物件及陣列。
2. Permanet Generation空間滿
PermanetGeneration中存放的為一些class的資訊等,當系統中要載入的類、反射的類和呼叫的方法較多時,Permanet Generation可能會被佔滿,在未配置為採用CMS GC的情況下會執行Full GC。如果經過Full GC仍然回收不了,那麼JVM會丟擲如下錯誤資訊: java.lang.OutOfMemoryError: PermGen space 為避免Perm Gen佔滿造成Full GC現象,可採用的方法為增大Perm Gen空間或轉為使用CMS GC。
3.CMS GC時出現promotion failed和concurrent mode failure
對於採用CMS進行舊生代GC的程式而言,尤其要注意GC日誌中是否有promotion failed和concurrent mode failure兩種狀況,當這兩種狀況出現時可能會觸發Full GC。
promotion failed是在進行Minor GC時,survivor space放不下、物件只能放入舊生代,而此時舊生代也放不下造成的;
concurrent mode failure是在執行CMS GC的過程中同時有物件要放入舊生代,而此時舊生代空間不足造成的。 應對措施為:增大survivor space、舊生代空間或調低觸發併發GC的比率,但在JDK 5.0+、6.0+的版本中有可能會由於JDK的bug29導致CMS在remark完畢後很久才觸發sweeping動作。對於這種狀況,可透過設定-XX:CMSMaxAbortablePrecleanTime=5(單位為ms)來避免。
統計得到的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間
這是一個較為複雜的觸發情況,Hotspot為了避免由於新生代物件晉升到舊生代導致舊生代空間不足的現象,在進行MinorGC時,做了一個判斷,如果之前統計所得到的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間,那麼就直接觸發Full GC。
例如程式第一次觸發MinorGC後,有6MB的物件晉升到舊生代,那麼當下一次Minor GC發生時,首先檢查舊生代的剩餘空間是否大於6MB,如果小於6MB,則執行Full GC。
當新生代採用PSGC時,方式稍有不同,PS GC是在Minor GC後也會檢查,例如上面的例子中第一次Minor GC後,PS GC會檢查此時舊生代的剩餘空間是否大於6MB,如小於,則觸發對舊生代的回收。
除了以上4種狀況外,對於使用RMI來進行RPC或管理的Sun JDK應用而言,預設情況下會一小時執行一次Full GC。可透過在啟動時透過- java-Dsun.rmi.dgc.client.gcInterval=3600000來設定Full GC執行的間隔時間或透過-XX:+DisableExplicitGC來禁止RMI呼叫System.gc。
什麼是Java虛擬機器?為什麼Java被稱作是“平臺無關的程式語言?
Java虛擬機器是一個可以執行Java位元組碼的虛擬機器程序。Java原始檔被編譯成能被Java虛擬機器執行的位元組碼檔案。 Java被設計成允許應用程式可以執行在任意的平臺,而不需要程式設計師為每一個平臺單獨重寫或者是重新編譯。Java虛擬機器讓這個變為可能,因為它知道底層硬體平臺的指令長度和其他特性。