面試京東Java崗,三問JVM被刷,我回家后仔細(xì)總結(jié)了這份JVM面試題

前言

JVM作為一個(gè)重要的知識(shí)點(diǎn),在面試中也是尤為重要的,面試之前就有朋友提醒過,要多去了解學(xué)習(xí),從當(dāng)前的一個(gè)就業(yè)形勢來說,不僅對于基本操作內(nèi)容要有良好的見地,面試官更多的也在考察你對他人不熟悉的技術(shù)點(diǎn)的認(rèn)知情況。

其實(shí)在寫出本篇文章之前,我也找過很多相關(guān)的知識(shí)點(diǎn)內(nèi)容,并進(jìn)行了了解,奈何沒有上心,導(dǎo)致面試的時(shí)候紕漏百出,結(jié)果自然是遺憾退場! 所以今天在這里給大家把這次的知識(shí)點(diǎn)總結(jié)上! 文中內(nèi)容也多有借鑒他人經(jīng)驗(yàn),中間也有我自己的一個(gè)想法在里面進(jìn)行了再加工,希望能對大家下次的面試有所幫助。

那么,廢話不多說,直接上干貨......

一、java內(nèi)存區(qū)域

1、jvm包含了哪幾個(gè)模塊,以及各個(gè)模塊的作用?

這張圖我們要印象深刻,JVM包含兩個(gè)子系統(tǒng)和兩個(gè)組件,兩個(gè)子系統(tǒng)為Class loader(類裝載)、Execution engine(執(zhí)行引擎);兩個(gè)組件為Runtime data area(運(yùn)行時(shí)數(shù)據(jù)區(qū))、Native Interface(本地接口)。

每個(gè)模塊的作用:

(1)首先通過編譯器把 Java 代碼轉(zhuǎn)換成字節(jié)碼,

(2)類加載器(ClassLoader)再把字節(jié)碼加載到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime data area)的方法區(qū)內(nèi),

(3)而字節(jié)碼文件只是 JVM 的一套指令集規(guī)范,并不能直接交給底層操作系統(tǒng)去執(zhí)行,因此需要特定的命令解析器執(zhí)行引擎(Execution Engine),將字節(jié)碼翻譯成底層系統(tǒng)指令,再交由 CPU 去執(zhí)行,而這個(gè)過程中需要調(diào)用其他語言的本地庫接口(Native Interface)來實(shí)現(xiàn)整個(gè)程序的功能。

2、說一下 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)

Java 虛擬機(jī)在執(zhí)行 Java 程序的過程中會(huì)把它所管理的內(nèi)存區(qū)域劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。注意是在執(zhí)行java程序的時(shí)候劃分的,Java 虛擬機(jī)所管理的內(nèi)存被劃分為如下幾個(gè)區(qū)域:

(1)程序計(jì)數(shù)器(Program Counter Register):當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器,字節(jié)碼解析器的工作是通過改變這個(gè)計(jì)數(shù)器的值,來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能,都需要依賴這個(gè)計(jì)數(shù)器來完成;

(2)Java 虛擬機(jī)棧(Java Virtual Machine Stacks):用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息;

(3)本地方法棧(Native Method Stack):與虛擬機(jī)棧的作用是一樣的,只不過虛擬機(jī)棧是服務(wù) Java 方法的,而本地方法棧是為虛擬機(jī)調(diào)用 Native 方法服務(wù)的;

(4)Java 堆(Java Heap):Java 虛擬機(jī)中內(nèi)存最大的一塊,是被所有線程共享的,幾乎所有的對象實(shí)例都在這里分配內(nèi)存;

(5)方法區(qū)(Methed Area):用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯后的代碼等數(shù)據(jù)。

3、說一下堆和棧的區(qū)別?

(1)物理內(nèi)存

堆的物理地址分配對對象是不連續(xù)的。因此性能慢些。在GC的時(shí)候也要考慮到不連續(xù)的分配,所以有各種算法。比如,標(biāo)記-消除,復(fù)制,標(biāo)記-壓縮,分代(即新生代使用復(fù)制算法,老年代使用標(biāo)記——壓縮)

棧使用的是數(shù)據(jù)結(jié)構(gòu)中的棧,先進(jìn)后出的原則,物理地址分配是連續(xù)的。所以性能快。

(2)存放的內(nèi)容

堆存放的是對象的實(shí)例和數(shù)組。因此該區(qū)更關(guān)注的是數(shù)據(jù)的存儲(chǔ)

棧存放:局部變量,操作數(shù)棧,返回結(jié)果。該區(qū)更關(guān)注的是程序方法的執(zhí)行。

(3)程序的可見度

堆對于整個(gè)應(yīng)用程序都是共享、可見的。

棧只對于線程是可見的。所以也是線程私有。他的生命周期和線程相同。

4、隊(duì)列和棧是什么?有什么區(qū)別?

操作的名稱不同(入隊(duì)出隊(duì)、入棧出棧),操作的位置不同(隊(duì)頭),方式不同。

二、java虛擬機(jī)中的對象

1、一個(gè)java對象是如何創(chuàng)建的?

(1)虛擬機(jī)遇到一條new指令時(shí),先檢查常量池是否已經(jīng)加載相應(yīng)的類,

(2)如果沒有,必須先執(zhí)行相應(yīng)的類加載。

(3)類加載通過后,接下來分配內(nèi)存。若Java堆中內(nèi)存是絕對規(guī)整的,使用“指針碰撞“方式分配內(nèi)存;如果不是規(guī)整的,就從空閑列表中分配,叫做”空閑列表“方式。

(4)劃分內(nèi)存時(shí)還需要考慮一個(gè)問題-并發(fā),也有兩種方式: CAS同步處理,或者本地線程分配緩沖(Thread Local Allocation Buffer, TLAB)。

(5)然后內(nèi)存空間初始化操作,

(6)接著是做一些必要的對象設(shè)置(元信息、哈希碼…),最后執(zhí)行<init style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit;">方法。</init>

2、對象創(chuàng)建有哪幾種方式?

Header 解釋
使用new關(guān)鍵字 調(diào)用了構(gòu)造函數(shù)
使用Class的newInstance方法 調(diào)用了構(gòu)造函數(shù)
使用Constructor類的newInstance方法 調(diào)用了構(gòu)造函數(shù)
使用clone方法 沒有調(diào)用構(gòu)造函數(shù)
使用反序列化 沒有調(diào)用構(gòu)造函數(shù)

3、如何為對象分配內(nèi)存?

類加載完成后,接著會(huì)在Java堆中劃分一塊內(nèi)存分配給對象。內(nèi)存分配根據(jù)Java堆是否規(guī)整,有兩種方式:

(1)指針碰撞:如果Java堆的內(nèi)存是規(guī)整,即所有用過的內(nèi)存放在一邊,而空閑的的放在另一邊。分配內(nèi)存時(shí)將位于中間的指針指示器向空閑的內(nèi)存移動(dòng)一段與對象大小相等的距離,這樣便完成分配內(nèi)存工作。

(2)空閑列表:如果Java堆的內(nèi)存不是規(guī)整的,則需要由虛擬機(jī)維護(hù)一個(gè)列表來記錄那些內(nèi)存是可用的,這樣在分配的時(shí)候可以從列表中查詢到足夠大的內(nèi)存分配給對象,并在分配后更新列表記錄。

選擇哪種分配方式是由 Java 堆是否規(guī)整來決定的,而 Java 堆是否規(guī)整又由所采用的垃圾收集器是否帶有壓縮整理功能決定。

4、為對象分配內(nèi)存時(shí),如何處理并發(fā)安全問題?

對象的創(chuàng)建在虛擬機(jī)中是一個(gè)非常頻繁的行為,哪怕只是修改一個(gè)指針?biāo)赶虻奈恢?,在并發(fā)情況下也是不安全的,可能出現(xiàn)正在給對象 A 分配內(nèi)存,指針還沒來得及修改,對象 B 又同時(shí)使用了原來的指針來分配內(nèi)存的情況。解決這個(gè)問題有兩種方案:

5、如何定位一個(gè)堆上的對象?

Java程序需要通過 JVM 棧上的引用訪問堆中的具體對象。對象的訪問方式取決于 JVM 虛擬機(jī)的實(shí)現(xiàn)。目前主流的訪問方式有 句柄 和 直接指針 兩種方式。

(1)指針:如果使用直接指針訪問,引用 中存儲(chǔ)的直接就是對象地址,那么Java堆對象內(nèi)部的布局中就必須考慮如何放置訪問類型數(shù)據(jù)的相關(guān)信息。

(2)句柄:句柄不直接指向?qū)ο?,而是指向?qū)ο蟮闹羔?,再由對象的指針指向?qū)ο蟮恼鎸?shí)內(nèi)存地址,句柄中包含了對象實(shí)例數(shù)據(jù)對象類型數(shù)據(jù)各自的具體地址信息。

6、Java會(huì)存在內(nèi)存泄漏嗎?請簡單描述

內(nèi)存泄漏是指不再被使用的對象或者變量一直被占據(jù)在內(nèi)存中。理論上來說,Java是有GC垃圾回收機(jī)制的,也就是說,不再被使用的對象,會(huì)被GC自動(dòng)回收掉,自動(dòng)從內(nèi)存中清除。

但是,即使這樣,Java也還是存在著內(nèi)存泄漏的情況,java導(dǎo)致內(nèi)存泄露的原因很明確:長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對象已經(jīng)不再需要,但是因?yàn)殚L生命周期對象持有它的引用而導(dǎo)致不能被回收,這就是java中內(nèi)存泄露的發(fā)生場景。

三、垃圾回收

1、簡述Java垃圾回收機(jī)制

在java中,程序員是不需要顯示的去釋放一個(gè)對象的內(nèi)存的,而是由虛擬機(jī)自行執(zhí)行。在JVM中,有一個(gè)垃圾回收線程,它是低優(yōu)先級的,在正常情況下是不會(huì)執(zhí)行的,只有在虛擬機(jī)空閑或者當(dāng)前堆內(nèi)存不足時(shí),才會(huì)觸發(fā)執(zhí)行,掃面那些沒有被任何引用的對象,并將它們添加到要回收的集合中,進(jìn)行回收。

回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java 提供的 GC 功能可以自動(dòng)監(jiān)測對象是否超過作用域從而達(dá)到自動(dòng)

回收內(nèi)存的目的,Java 語言沒有提供釋放已分配內(nèi)存的顯示操作方法

2、垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收內(nèi)存嗎?有什么辦法主動(dòng)通知虛擬機(jī)進(jìn)行垃圾回收?

(1)對于GC來說,當(dāng)程序員創(chuàng)建對象時(shí),GC就開始監(jiān)控這個(gè)對象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是"可達(dá)的",哪些對象是"不可達(dá)的"。當(dāng)GC確定一些對象為"不可達(dá)"時(shí),GC就有責(zé)任回收這些內(nèi)存空間。

(2)垃圾回收器可以馬上回收內(nèi)存。

(3)程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語言規(guī)范并不保證GC一定會(huì)執(zhí)行。

3、Java 中都有哪些引用類型?

(1)強(qiáng)引用:發(fā)生 gc 的時(shí)候不會(huì)被回收。

(2)軟引用:有用但不是必須的對象,在發(fā)生內(nèi)存溢出之前會(huì)被回收。

(3)弱引用:有用但不是必須的對象,在下一次GC時(shí)會(huì)被回收。

(4)虛引用(幽靈引用/幻影引用):無法通過虛引用獲得對象,用 PhantomReference 實(shí)現(xiàn)虛引用,虛引用的用途是在 gc 時(shí)返回一個(gè)通知。

4、怎么判斷對象是否可以被回收?

垃圾收集器在做垃圾回收的時(shí)候,首先需要判定的就是哪些內(nèi)存是需要被回收的,哪些對象是「存活」的,是不可以被回收的;哪些對象已經(jīng)「死掉」了,需要被回收。

一般有兩種方法來判斷:

(1)引用計(jì)數(shù)器法:為每個(gè)對象創(chuàng)建一個(gè)引用計(jì)數(shù),有對象引用時(shí)計(jì)數(shù)器 +1,引用被釋放時(shí)計(jì)數(shù) -1,當(dāng)計(jì)數(shù)器為 0 時(shí)就可以被回收。它有一個(gè)缺點(diǎn)不能解決循環(huán)引用的問題;

(2)可達(dá)性分析算法:從 GC Roots 開始向下搜索,搜索所走過的路徑稱為引用鏈。當(dāng)一個(gè)對象到 GC Roots 沒有任何引用鏈相連時(shí),則證明此對象是可以被回收的。

5、在Java中,對象什么時(shí)候可以被垃圾回收?

當(dāng)對象對當(dāng)前使用這個(gè)對象的應(yīng)用程序變得不可觸及的時(shí)候,這個(gè)對象就可以被回收了。
垃圾回收會(huì)發(fā)生在永久代,如果永久代滿了或者是超過了臨界值,會(huì)觸發(fā)完全垃圾回收(Full GC)。

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

(1)標(biāo)記-清除算法:標(biāo)記無用對象,然后進(jìn)行清除回收。缺點(diǎn):效率不高,無法清除垃圾碎片。

(2)復(fù)制算法:按照容量劃分二個(gè)大小相等的內(nèi)存區(qū)域,當(dāng)一塊用完的時(shí)候?qū)⒒钪膶ο髲?fù)制到另一塊上,然后再把已使用的內(nèi)存空間一次清理掉。缺點(diǎn):內(nèi)存使用率不高,只有原來的一半。

(3)標(biāo)記-整理算法:標(biāo)記無用對象,讓所有存活的對象都向一端移動(dòng),然后直接清除掉端邊界以外的內(nèi)存。缺點(diǎn):仍需要進(jìn)行局部對象移動(dòng),一定程度上降低了效率。

(4)分代算法:根據(jù)對象存活周期的不同將內(nèi)存劃分為幾塊,一般是新生代和老年代,新生代基本采用復(fù)制算法,老年代采用標(biāo)記整理算法。

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

其中用于回收新生代的收集器包括Serial、PraNew、Parallel Scavenge,回收老年代的收集器包括Serial Old、Parallel Old、CMS,還有用于回收整個(gè)Java堆的G1收集器。不同收集器之間的連線表示它們可以搭配使用。

(1)Serial收集器(復(fù)制算法): 新生代單線程收集器,標(biāo)記和清理都是單線程,優(yōu)點(diǎn)是簡單高效;

(2)ParNew收集器 (復(fù)制算法): 新生代收并行集器,實(shí)際上是Serial收集器的多線程版本,在多核CPU環(huán)境下有著比Serial更好的表現(xiàn);

(3)Parallel Scavenge收集器 (復(fù)制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用戶線程時(shí)間/(用戶線程時(shí)間+GC線程時(shí)間),高吞吐量可以高效率的利用CPU時(shí)間,盡快完成程序的運(yùn)算任務(wù),適合后臺(tái)應(yīng)用等對交互相應(yīng)要求不高的場景;

(4)Serial Old收集器 (標(biāo)記-整理算法): 老年代單線程收集器,Serial收集器的老年代版本;

(5)Parallel Old收集器 (標(biāo)記-整理算法):老年代并行收集器,吞吐量優(yōu)先,Parallel Scavenge收集器的老年代版本;

(6)CMS(Concurrent Mark Sweep)收集器(標(biāo)記-清除算法):老年代并行收集器,以獲取最短回收停頓時(shí)間為目標(biāo)的收集器,具有高并發(fā)、低停頓的特點(diǎn),追求最短GC回收停頓時(shí)間。

(7)G1(Garbage First)收集器 (標(biāo)記-整理算法):Java堆并行收集器,G1收集器是JDK1.7提供的一個(gè)新收集器,G1收集器基于“標(biāo)記-整理”算法實(shí)現(xiàn),也就是說不會(huì)產(chǎn)生內(nèi)存碎片。此外,G1收集器不同于之前的收集器的一個(gè)重要特點(diǎn)是:G1回收的范圍是整個(gè)Java堆(包括新生代,老年代),而前六種收集器回收的范圍僅限于新生代或老年代。

8、介紹一下 CMS 垃圾回收器?

CMS 是英文 Concurrent Mark-Sweep 的簡稱,是以犧牲吞吐量為代價(jià)來獲得最短回收停頓時(shí)間的垃圾回收器。對于要求服務(wù)器響應(yīng)速度的應(yīng)用上,這種垃圾回收器非常適合。在啟動(dòng) JVM 的參數(shù)加上“-XX:+UseConcMarkSweepGC”來指定使用 CMS 垃圾回收器。

CMS 使用的是標(biāo)記-清除的算法實(shí)現(xiàn)的,所以在 gc 的時(shí)候回產(chǎn)生大量的內(nèi)存碎片,當(dāng)剩余內(nèi)存不能滿足程序運(yùn)行要求時(shí),系統(tǒng)將會(huì)出現(xiàn) Concurrent Mode Failure,臨時(shí) CMS 會(huì)采用 Serial Old 回收器進(jìn)行垃圾清除,此時(shí)的性能將會(huì)被降低。

9、簡述分代垃圾回收器是怎么工作的?

分代回收器有兩個(gè)分區(qū):老生代和新生代,新生代默認(rèn)的空間占比總空間的 1/3,老生代的默認(rèn)占比是 2/3。

新生代使用的是復(fù)制算法,新生代里有 3 個(gè)分區(qū):Eden、To Survivor、From Survivor,它們的默認(rèn)占比是 8:1:1,它的執(zhí)行流程如下:

(1)把 Eden + From Survivor 存活的對象放入 To Survivor 區(qū);

(2)清空 Eden 和 From Survivor 分區(qū);

(3)From Survivor 和 To Survivor 分區(qū)交換,F(xiàn)rom Survivor 變 To Survivor,To Survivor 變 From Survivor。

每次在 From Survivor 到 To Survivor 移動(dòng)時(shí)都存活的對象,年齡就 +1,當(dāng)年齡到達(dá) 15(默認(rèn)配置是 15)時(shí),升級為老生代。大對象也會(huì)直接進(jìn)入老生代。

老生代當(dāng)空間占用到達(dá)某個(gè)值之后就會(huì)觸發(fā)全局垃圾收回,一般使用標(biāo)記整理的執(zhí)行算法。以上這些循環(huán)往復(fù)就構(gòu)成了整個(gè)分代垃圾回收的整體執(zhí)行流程。

四、內(nèi)存分配策略

1、簡述java內(nèi)存分配與回收策率?

所謂自動(dòng)內(nèi)存管理,最終要解決的也就是內(nèi)存分配和內(nèi)存回收兩個(gè)問題。前面我們介紹了內(nèi)存回收,這里我們再來聊聊內(nèi)存分配。

對象的內(nèi)存分配通常是在 Java 堆上分配(隨著虛擬機(jī)優(yōu)化技術(shù)的誕生,某些場景下也會(huì)在棧上分配,后面會(huì)詳細(xì)介紹),對象主要分配在新生代的 Eden 區(qū),如果啟動(dòng)了本地線程緩沖,將按照線程優(yōu)先在 TLAB 上分配。少數(shù)情況下也會(huì)直接在老年代上分配。總的來說分配規(guī)則不是百分百固定的,其細(xì)節(jié)取決于哪一種垃圾收集器組合以及虛擬機(jī)相關(guān)參數(shù)有關(guān)。

2、簡述Minor GC和Major GC?

多數(shù)情況,對象都在新生代 Eden 區(qū)分配。當(dāng) Eden 區(qū)分配沒有足夠的空間進(jìn)行分配時(shí),虛擬機(jī)將會(huì)發(fā)起一次 Minor GC。如果本次 GC 后還是沒有足夠的空間,則將啟用分配擔(dān)保機(jī)制在老年代中分配內(nèi)存。

這里我們提到 Minor GC,如果你仔細(xì)觀察過 GC 日常,通常我們還能從日志中發(fā)現(xiàn) Major GC/Full GC。

(1)Minor GC 是指發(fā)生在新生代的 GC,因?yàn)?Java 對象大多都是朝生夕死,所有 Minor GC 非常頻繁,一般回收速度也非???;

(2)Major GC/Full GC 是指發(fā)生在老年代的 GC,出現(xiàn)了 Major GC 通常會(huì)伴隨至少一次 Minor GC。Major GC 的速度通常會(huì)比 Minor GC 慢 10 倍以上。

3、對象何時(shí)進(jìn)入老年代

所謂大對象是指需要大量連續(xù)內(nèi)存空間的對象,頻繁出現(xiàn)大對象是致命的,會(huì)導(dǎo)致在內(nèi)存還有不少空間的情況下提前觸發(fā) GC 以獲取足夠的連續(xù)空間來安置新對象。

(1)如果大對象直接在新生代分配就會(huì)導(dǎo)致 Eden 區(qū)和兩個(gè) Survivor 區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。因此對于大對象都會(huì)直接在老年代進(jìn)行分配。

(2)虛擬機(jī)給每個(gè)對象定義了一個(gè)對象年齡的計(jì)數(shù)器,如果對象在 Eden 區(qū)出生,并且能夠被 Survivor 容納,將被移動(dòng)到 Survivor 空間中,這時(shí)設(shè)置對象年齡為 1。對象在 Survivor 區(qū)中每「熬過」一次 Minor GC 年齡就加 1,當(dāng)年齡達(dá)到一定程度(默認(rèn) 15) 就會(huì)被晉升到老年代。

五、類加載機(jī)制

1、描述一下JVM加載Class文件的原理機(jī)制

Java中的所有類,都需要由類加載器裝載到JVM中才能運(yùn)行。類加載器本身也是一個(gè)類,而它的工作就是把class文件從硬盤讀取到內(nèi)存中。類裝載方式,有兩種 :

(1)隱式裝載, 程序在運(yùn)行過程中當(dāng)碰到通過new 等方式生成對象時(shí),隱式調(diào)用類裝載器加載對應(yīng)的類到j(luò)vm中,

(2)顯式裝載, 通過class.forname()等方法,顯式加載需要的類

Java類的加載是動(dòng)態(tài)的,它并不會(huì)一次性將所有類全部加載后再運(yùn)行,而是保證程序運(yùn)行的基礎(chǔ)類(像是基類)完全加載到j(luò)vm中,至于其他類,則在需要的時(shí)候才加載。這當(dāng)然就是為了節(jié)省內(nèi)存開銷。

2、什么是類加載器,類加載器有哪些?

主要有一下四種類加載器:

(1)啟動(dòng)類加載器(Bootstrap ClassLoader)用來加載java核心類庫,無法被java程序直接引用。

(2)擴(kuò)展類加載器(extensions class loader):它用來加載 Java 的擴(kuò)展庫。Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫目錄。該類加載器在此目錄里面查找并加載 Java 類。

(3)系統(tǒng)類加載器(system class loader):它根據(jù) Java 應(yīng)用的類路徑(CLASSPATH)來加載 Java 類。一般來說,Java 應(yīng)用的類都是由它來完成加載的??梢酝ㄟ^ ClassLoader.getSystemClassLoader()來獲取它。

(4)用戶自定義類加載器,通過繼承 java.lang.ClassLoader類的方式實(shí)現(xiàn)。

3、說一下類裝載的執(zhí)行過程?

類裝載分為以下 5 個(gè)步驟:

(1)加載:根據(jù)查找路徑找到相應(yīng)的 class 文件然后導(dǎo)入;

(2)驗(yàn)證:檢查加載的 class 文件的正確性;

(3)準(zhǔn)備:給類中的靜態(tài)變量分配內(nèi)存空間;

(4)解析:虛擬機(jī)將常量池中的符號(hào)引用替換成直接引用的過程。符號(hào)引用就理解為一個(gè)標(biāo)示,而在直接引用直接指向內(nèi)存中的地址;

(5)初始化:對靜態(tài)變量和靜態(tài)代碼塊執(zhí)行初始化工作。

4、什么是雙親委派模型?

雙親委派模型:如果一個(gè)類加載器收到了類加載的請求,它首先不會(huì)自己去加載這個(gè)類,而是把這個(gè)請求委派給父類加載器去完成,每一層的類加載器都是如此,這樣所有的加載請求都會(huì)被傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父加載無法完成加載請求(它的搜索范圍中沒找到所需的類)時(shí),子加載器才會(huì)嘗試去加載類。

當(dāng)一個(gè)類收到了類加載請求時(shí),不會(huì)自己先去加載這個(gè)類,而是將其委派給父類,由父類去加載,如果此時(shí)父類不能加載,反饋給子類,由子類去完成類的加載。

5、類的生命周期?

類的生命周期包括這幾個(gè)部分,加載、連接、初始化、使用和卸載,其中前三部是類的加載的過程,如下圖;

(1)加載,查找并加載類的二進(jìn)制數(shù)據(jù),在堆中也創(chuàng)建一個(gè)java.lang.Class類的對象

(2)連接,連接又包含三塊內(nèi)容:驗(yàn)證、準(zhǔn)備、初始化。1)驗(yàn)證,文件格式、元數(shù)據(jù)、字節(jié)碼、符號(hào)引用驗(yàn)證;2)準(zhǔn)備,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值;3)解析,把類中的符號(hào)引用轉(zhuǎn)換為直接引用

(3)初始化,為類的靜態(tài)變量賦予正確的初始值

(4)使用,new出對象程序中使用

(5)卸載,執(zhí)行垃圾回收

六、JVM調(diào)優(yōu)

1、說一下 JVM 調(diào)優(yōu)的工具?

JDK 自帶了很多監(jiān)控工具,都位于 JDK 的 bin 目錄下,其中最常用的是 jconsole 和 jvisualvm 這兩款視圖監(jiān)控工具。

(1)jconsole:用于對 JVM 中的內(nèi)存、線程和類等進(jìn)行監(jiān)控;

(2)jvisualvm:JDK 自帶的全能分析工具,可以分析:內(nèi)存快照、線程快照、程序死鎖、監(jiān)控內(nèi)存的變化、gc 變化等。

2、常用的 JVM 調(diào)優(yōu)的參數(shù)都有哪些?

-Xms2g:初始化推大小為 2g;

-Xmx2g:堆最大內(nèi)存為 2g;

-XX:NewRatio=4:設(shè)置年輕的和老年代的內(nèi)存比例為 1:4;

-XX:SurvivorRatio=8:設(shè)置新生代 Eden 和 Survivor 比例為 8:2;

–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器組合;

-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器組合;

-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器組合;

-XX:+PrintGC:開啟打印 gc 信息;

-XX:+PrintGCDetails:打印 gc 詳細(xì)信息。

OK,jvm系列的面試題,我找了找其他的,基本上都一樣,里面我補(bǔ)充了一部分,也去掉了一部分。

最后,今天的分享到這里就結(jié)束了,以上的內(nèi)容大家可以多在面試之前之前去突擊一下,相信會(huì)有不錯(cuò)效果出現(xiàn), 如需獲取更多面試資料請?jiān)?strong>后臺(tái)私信: 面試 獲取即可!

全網(wǎng)最全的大廠面試真題都在這里了

感謝閱讀,關(guān)注、轉(zhuǎn)發(fā)、評論表明一下你對小編的支持,也是很不錯(cuò)的!后續(xù)將分享更多干貨給大家!>_<

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容