java架構師面試題
比較全的面試題目
JVM 常見面試題進階
提示:
再把“Java核心知識點整理”的jvm部分加上,也看看,整合到一起。
1.1 Java 語言怎麼實作跨平台的?
我們編寫的 Java 源碼,編譯後會生成一種 .class 檔案,稱為位元組碼檔案。位元組碼不能直接運作,必須通過 JVM 翻譯成機器碼才能運作。
JVM 是一個”橋梁“,是一個”中間件“,是實作跨平台的關鍵。Java 代碼首先被編譯成位元組碼檔案,再由 JVM 将位元組碼檔案翻譯成機器語言,進而達到運作 Java 程式的目的。
1.2 JVM 資料運作區,哪些會造成 OOM 的情況?
除了資料運作區,其他區域均有可能造成 OOM 的情況。
堆溢出:java.lang.OutOfMemoryError: Java heap space
棧溢出:java.lang.StackOverflowError
永久代溢出:java.lang.OutOfMemoryError:PermGen space
1.3 詳細介紹一下對象在分代記憶體區域的配置設定過程?
- JVM 會試圖為相關 Java 對象在 Eden 中初始化一塊記憶體區域。
- 當 Eden 空間足夠時,記憶體申請結束;否則到下一步。
- JVM 試圖釋放在 Eden 中所有不活躍的對象(這屬于 1 或更進階的垃圾回收)。釋放後若 Eden 空間仍然不足以放入新對象,則試圖将部分 Eden 中活躍對象放入 Survivor 區。
- Survivor 區被用來作為 Eden 及 Old 的中間交換區域,當 Old 區空間足夠時,Survivor 區的對象會被移到 Old 區,否則會被保留在 Survivor 區。
- 當 Old 區空間不夠時,JVM 會在 Old 區進行完全的垃圾收集。
- 完全垃圾收集後,若 Survivor 及 Old 區仍然無法存放從 Eden 複制過來的部分對象,導緻 JVM 無法在 Eden 區為新對象建立記憶體區域,則出現 “ out of memory ” 錯誤。
1.4 G1 與 CMS 兩個垃圾收集器的對比
細節方面不同
- G1 在壓縮空間方面有優勢。
- G1 通過将記憶體空間分成區域(Region)的方式避免記憶體碎片問題。
- Eden, Survivor, Old 區不再固定、在記憶體使用效率上來說更靈活。
- G1 可以通過設定預期停頓時間(Pause Time)來控制垃圾收集時間避免應用雪崩現象。
- G1 在回收記憶體後會馬上同時做合并空閑記憶體的工作、而 CMS 預設是在 STW(stop the world)的時候做。
- G1 會在 新生代和年老代 中使用、而 CMS 隻能在 O 區使用。
- 整體内容不同
吞吐量優先:G1
響應優先:CMS
CMS 的缺點是對 cpu 的要求比較高。G1 是将記憶體化成了多塊,所有對内段的大小有很大的要求。
CMS 是清除,是以會存在很多的記憶體碎片。G1 是整理,是以碎片空間較小。
1.5 線上常用的 JVM 參數有哪些?
資料區設定
Xms:初始堆大小
Xmx:最大堆大小
Xss:Java 每個線程的Stack大小
XX:NewSize=n:設定年輕代大小
XX:NewRatio=n:設定年輕代和年老代的比值。如:為 3,表示年輕代與年老代比值為 1:3,年輕代占整個年輕代年老代和的 1/4。
XX:SurvivorRatio=n:年輕代中 Eden 區與兩個 Survivor 區的比值。注意 Survivor 區有兩個。如:3,表示 Eden:Survivor=3:2,一個 Survivor 區占整個年輕代的 1/5。
XX:MaxPermSize=n:設定持久代大小。
JvM 參數調優:
一 xms < size >表示jvM 初始化堆的大小, : Xmx < size >表示 JvM 堆的最大值。這兩個值的大小一般根據需要進行設定。當應用程式需要的記憶體超出堆的最大值時虛拟機就會提示記憶體溢出,并且導緻應用服務崩潰。是以一般建議堆的最大值設定為可用記憶體的最大值的 80 %。
在 catalina . bat 中,設定 JAvA _ OPTS = ’一 Xms256m - Xmxs 12m ' ,表示初始化記憶體為 256MB ,可以使用的最大記憶體為 51 ZMB 。
收集器設定
XX:+UseSerialGC:設定串行收集器
XX:+UseParallelGC::設定并行收集器
XX:+UseParalledlOldGC:設定并行年老代收集器
XX:+UseConcMarkSweepGC:設定并發收集器
GC日志列印設定
XX:+PrintGC:列印 GC 的簡要資訊
XX:+PrintGCDetails:列印 GC 詳細資訊
XX:+PrintGCTimeStamps:輸出 GC 的時間戳
1.6 對象什麼時候進入老年代?
對象優先在 Eden 區配置設定記憶體
當對象首次建立時, 會放在新生代的 eden 區, 若沒有 GC 的介入,會一直在 eden 區,GC 後,是可能進入 survivor 區或者年老代
大對象直接進入老年代
所謂的大對象是指需要大量連續記憶體空間的 Java 對象,最典型的大對象就是那種很長的字元串以及數組,大對象對虛拟機的記憶體配置設定就是壞消息,尤其是一些朝生夕滅的短命大對象,寫程式時應避免。
長期存活的對象進入老年代
虛拟機給每個對象定義了一個對象年齡(Age)計數器,對象在 Survivor 區中每熬過一次 Minor GC,年齡就增加 1,當他的年齡增加到一定程度(預設是 15 歲), 就将會被晉升到老年代中。
1.7 什麼是記憶體溢出, 記憶體洩露? 他們的差別是什麼?
記憶體溢出 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現 out of memory;
記憶體洩露 memory leak,是指程式在申請記憶體後,無法釋放已申請的記憶體空間,一次記憶體洩露危害可以忽略,但記憶體洩露堆積後果很嚴重,無論多少記憶體,遲早會被占光。
記憶體溢出就是你要求配置設定的記憶體超出了系統能給你的,系統不能滿足需求,于是産生溢出。
記憶體洩漏是指你向系統申請配置設定記憶體進行使用(new),可是使用完了以後卻不歸還(delete),結果你申請到的那塊記憶體你自己也不能再通路(也許你把它的位址給弄丢了),而系統也不能再次将它配置設定給需要的程式。
什麼情況下會出現棧溢出
- 方法建立了一個很大的對象,如 List,Array。
- 是否産生了循環調用、死循環。
- 是否引用了較大的全局變量。
1.8 引起類加載操作的行為有哪些?
- 遇到 new、getstatic、putstatic 或 invokestatic 這四條位元組碼指令。
- 反射調用的時候,如果類沒有進行過初始化,則需要先觸發其初始化。
- 子類初始化的時候,如果其父類還沒初始化,則需先觸發其父類的初始化。
- 虛拟機執行主類的時候(有 main( string[] args))。
- JDK1.7 動态語言支援。
1.9 介紹一下 JVM 提供的常用工具
jps:用來顯示本地的 Java 程序,可以檢視本地運作着幾個 Java 程式,并顯示他們的程序号。 指令格式:jps
jinfo:運作環境參數:Java System 屬性和 JVM 指令行參數,Java class path 等資訊。 指令格式:jinfo 程序 pid
jstat:監視虛拟機各種運作狀态資訊的指令行工具。 指令格式:jstat -gc 123 250 20
jstack:可以觀察到 JVM 中目前所有線程的運作情況和線程目前狀态。 指令格式:jstack 程序 pid
jmap:觀察運作中的 JVM 實體記憶體的占用情況(如:産生哪些對象,及其數量)。 指令格式:jmap [option] pid
1.10 Full GC 、 Major GC 、Minor GC 之間差別?
Minor GC: 從新生代空間(包括 Eden 和 Survivor 區域)回收記憶體被稱為 Minor GC。
Major GC: 清理 Tenured 區,用于回收老年代,出現 Major GC 通常會出現至少一次 Minor GC。
Full GC: Full GC 是針對整個新生代、老年代、元空間(metaspace,java8 以上版本取代 perm gen)的全局範圍的 GC。
1.11 什麼時候觸發 Full GC ?
- 調用 System.gc 時,系統建議執行 Full GC,但是不必然執行。
- 老年代空間不足。
- 方法區空間不足。
- 通過 Minor GC 後進入老年代的平均大小大于老年代的可用記憶體。
- 由 Eden 區、survivor space1(From Space)區向 survivor space2(To Space)區複制時,對象大小大于 To Space 可用記憶體,則把該對象轉存到老年代,且老年代的可用記憶體小于該對象大小。
1.12 什麼情況下會出現棧溢出
- 方法建立了一個很大的對象,如 List,Array。
- 是否産生了循環調用、死循環。
- 是否引用了較大的全局變量。
1.13 說一下強引用、軟引用、弱引用、虛引用以及他們之間和 gc 的關系
強引用:new 出的對象之類的引用,隻要強引用還在,永遠不會回收。
軟引用:當系統記憶體足夠時它不會被回收,當系統記憶體空間不足時它會被回收。
弱引用:隻要垃圾回收機制一運作,不管 JVM 的記憶體空間是否足夠,總會回收該對象占用的記憶體。
虛引用:主要作用是跟蹤對象被垃圾回收的狀态。
1.14 Eden 和 Survivor 的比例配置設定是什麼情況?為什麼?
預設比例 8:1。 大部分對象都是朝生夕死。 複制算法的基本思想就是将記憶體分為兩塊,每次隻用其中一塊,當這一塊記憶體用完,就将還活着的對象複制到另外一塊上面。複制算法不會産生記憶體碎片。
實戰
JAVA 線上故障排查完整套路!
2.1 CPU 資源占用過高
- top 檢視目前 CPU 情況,找到占用 CPU 過高的程序 PID=123。
- top -H -p123 **可以找出兩個 CPU 占用較高的線程,**記錄下來 PID=2345, 3456 轉換為十六進制。
-
jstack -l 123 > temp.txt 列印出目前程序的線程棧。
可以觀察到 JVM 中目前所有線程的運作情況和線程目前狀态。
- 查找到對應于第二步的兩個線程運作棧,分析代碼。
2.2 OOM 異常排查
1.使用 top 指令查詢伺服器系統狀态。
\2. ps -aux|grep java 找出目前 Java 程序的 PID。
\3. jstat -gcutil pid interval 檢視目前 GC 的狀态。
\4. jmap -histo:live pid 可用統計存活對象的分布情況,從高到低檢視占據記憶體最多的對象。
\5. jmap -dump:format=b,file= 檔案名 [pid] 利用 Jmap dump。
\6. 使用性能分析工具對上一步 dump 出來的檔案進行分析,工具有 MAT 等。
JVM常見面試題基礎