1. 什么是JVM?
就是 JAVA 虛擬機(jī), 它只識別 .class 類型文件,它能夠?qū)?class 文件中的字節(jié)碼指令進(jìn)行識別并調(diào)用操作系統(tǒng)向上的 API 完成動作。
2. Java 代碼的運(yùn)行過程?
Java 源代碼 -> 編輯器 -> 字節(jié)碼文件
字節(jié)碼 -> JVM -> 機(jī)器碼文件
每一種平臺的解釋器是不同的,但是實(shí)現(xiàn)的虛擬機(jī)是相同的,這也就是 Java 為什么能夠
跨平臺的原因
3. JVM后臺常駐線程有?
- 虛擬機(jī)線程
- 周期任務(wù)線程
- Gc 線程
- 編輯器線程
- 信號分發(fā)線程
4. JVM內(nèi)存區(qū)域分為?
- 私有區(qū)域 ,包括程序計(jì)數(shù)器,虛擬機(jī)棧,本地方法區(qū)
- 線程共享區(qū),包括Java堆,方法區(qū)
- 直接內(nèi)存
線程私有數(shù)據(jù)區(qū)域生命周期與線程相同, 依賴用戶線程的啟動/結(jié)束 而 創(chuàng)建/銷毀(在 Hotspot
VM 內(nèi)
線程共享區(qū)域隨虛擬機(jī)的啟動/關(guān)閉而創(chuàng)建/銷毀
運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分。
5. 介紹下JAVA 虛擬機(jī)棧?
Java虛擬機(jī)棧是描述Java方法運(yùn)行過程的內(nèi)存模型。
Java虛擬機(jī)棧會為每一個(gè)即將運(yùn)行的方法分配“棧幀”空間,用于保存改方法運(yùn)行過程中所需要的一些信息,例如局部變量、操作數(shù)棧、動態(tài)鏈接、方法出口信息等。
Java虛擬機(jī)棧是由一個(gè)個(gè)棧幀組成,而每個(gè)棧幀中都擁有:局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口信息。
局部變量表的創(chuàng)建是在方法被執(zhí)行的時(shí)候,隨著棧幀的創(chuàng)建而創(chuàng)建。而且,局部變量表的大小在編譯時(shí)期就確定下來了,在創(chuàng)建的時(shí)候只需分配事先規(guī)定好的大小即可。
Java虛擬機(jī)棧會出現(xiàn)兩種異常:
StackOverFlowError
OutOfMemoryError
StackOverFlowError:當(dāng)線程請求棧的深度超過當(dāng)前Java虛擬機(jī)棧的最大深度的時(shí)候,就拋出StackOverFlowError異常。
OutOfMemoryError:
若Java虛擬機(jī)棧的內(nèi)存大小允許動態(tài)擴(kuò)展,且當(dāng)線程請求棧時(shí)內(nèi)存用完了,無法再動態(tài)擴(kuò)展了,此時(shí)拋出OutOfMemoryError異常。
6. 介紹下JAVA 堆?
線程共享 :整個(gè)Java虛擬機(jī)只有一個(gè)堆,所有的線程都訪問同一個(gè)堆。
在虛擬機(jī)啟動時(shí)創(chuàng)建。
垃圾回收的主要場所。
不同的區(qū)域存放具有不同生命周期的對象。這樣可以根據(jù)不同的區(qū)域使用不同的垃圾回收算法,從而更具有針對性,從而更高效。
堆的大小既可以固定也可以擴(kuò)展,但主流的虛擬機(jī)堆的大小是可擴(kuò)展的,因此當(dāng)線程請求分配內(nèi)存,但堆已滿,且內(nèi)存已滿無法再擴(kuò)展時(shí),就拋出OutOfMemoryError。
7. 介紹下JAVA 方法區(qū)?
方法區(qū)中存放已經(jīng)被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等。
方法區(qū)是堆的一個(gè)邏輯部分,因此和堆一樣,都是線程共享的。整個(gè)虛擬機(jī)中只有一個(gè)方法區(qū)。
方法區(qū)中的信息一般需要長期存在,而且它又是堆的邏輯分區(qū),因此用堆的劃分方法,我們把方法區(qū)稱為老年代。
對方法區(qū)的內(nèi)存回收的主要目標(biāo)是:對常量池的回收 和 對類型的卸載。長期存在。
方法區(qū)中存放數(shù)據(jù):類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼。其中常量存儲在運(yùn)行時(shí)常量池中。
常量池存在于方法區(qū)。
8. 從GC的角度,JAVA堆還可以怎么分?JVM運(yùn)行時(shí)內(nèi)存
- 新生代,包括Edan 區(qū),F(xiàn)rom Survivor 和 To Survivior
- 老年代
- 永久代
9. 介紹一下新生代
Edan區(qū) :Java新對象的出生地(如果新創(chuàng)建的對象占用內(nèi)存很大,則直接分配到老
年代)。當(dāng) Eden區(qū)內(nèi)存不夠的時(shí)候就會觸發(fā) MinorGC,對新生代區(qū)進(jìn)行
一次垃圾回收。Survivor From : 上一次 GC 的幸存者,作為這一次 GC 的被掃描者.
Survivor To : 保留了一次 MinorGC 過程中的幸存者.
10. MinorGC 的過程?
復(fù)制 , 清空, 互換
MinorGC 采用復(fù)制算法。
1: eden、 servicorFrom 復(fù)制到 ServicorTo,年齡+1
首先,把 Eden 和 ServivorFrom 區(qū)域中存活的對象復(fù)制到 ServicorTo 區(qū)域(如果有對象的年
齡以及達(dá)到了老年的標(biāo)準(zhǔn),則賦值到老年代區(qū)),同時(shí)把這些對象的年齡+1(如果 ServicorTo 不
夠位置了就放到老年區(qū));
2: 清空 eden、 servicorFrom
然后,清空 Eden 和 ServicorFrom 中的對象;
3: ServicorTo 和 ServicorFrom 互換
最后, ServicorTo 和 ServicorFrom 互換,原 ServicorTo 成為下一次 GC 時(shí)的 ServicorFrom
區(qū)。
11. 介紹下老年代和老年代的MajorGC?
老年代的對象比較穩(wěn)定,所以 MajorGC 不會頻繁執(zhí)行。在進(jìn)行 MajorGC 前一般都先進(jìn)行
了一次 MinorGC,使得有新生代的對象晉身入老年代,導(dǎo)致空間不夠用時(shí)才觸發(fā)。
MajorGC 采用標(biāo)記清除算法:首先掃描一次所有老年代,標(biāo)記出存活的對象,然后回收沒
有標(biāo)記的對象。 MajorGC 的耗時(shí)比較長,因?yàn)橐獟呙柙倩厥铡?MajorGC 會產(chǎn)生內(nèi)存碎片,為了減
少內(nèi)存損耗,我們一般需要進(jìn)行合并或者標(biāo)記出來方便下次直接分配。當(dāng)老年代也滿了裝不下的
時(shí)候,就會拋出 OOM(Out of Memory)異常。
12. 介紹下永久代?
主要存放 Class 和 Meta(元數(shù)據(jù))的信息,Class 在被加載的時(shí)候被
放入永久區(qū)域, 它和和存放實(shí)例的區(qū)域不同,GC 不會在主程序運(yùn)行期對永久區(qū)域進(jìn)行清理。所以這
也導(dǎo)致了永久代的區(qū)域會隨著加載的 Class 的增多而脹滿,最終拋出 OOM 異常。
當(dāng)對象在 Survivor 區(qū)躲過一次 GC 后,其年齡就會+1。 默認(rèn)情況下年齡到達(dá) 15 的對象會被
移到老生代中。
13. JAVA8 將永久代替換為元數(shù)據(jù)區(qū)
Java8 中, 永久代已經(jīng)被移除,被一個(gè)稱為“元數(shù)據(jù)區(qū)”(元空間)的區(qū)域所取代。元空間
的本質(zhì)和永久代類似,
元空間與永久代之間最大的區(qū)別在于: 元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。
因此,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制。
14. GC 如何確定是垃圾?
- 引用計(jì)數(shù)法
在 Java 中,引用和對象是有關(guān)聯(lián)的。如果要操作對象則必須用引用進(jìn)行。因此,很顯然一個(gè)簡單
的辦法是通過引用計(jì)數(shù)來判斷一個(gè)對象是否可以回收。簡單說,即一個(gè)對象如果沒有任何與之關(guān)
聯(lián)的引用, 即他們的引用計(jì)數(shù)都不為 0, 則說明對象不太可能再被用到,那么這個(gè)對象就是可回收
對象。
- 可達(dá)性分析
為了解決引用計(jì)數(shù)法的循環(huán)引用問題, Java 使用了可達(dá)性分析的方法。通過一系列的“GC roots”
對象作為起點(diǎn)搜索。如果在“GC roots”和一個(gè)對象之間沒有可達(dá)路徑,則稱該對象是不可達(dá)的
不可達(dá)對象不等價(jià)于可回收對象, 不可達(dá)對象變?yōu)榭苫厥諏ο笾辽僖?jīng)過兩次標(biāo)記
過程。
15. JAVA中的四種引用類型?
強(qiáng)引用,把一個(gè)對象賦給一個(gè)引用變量,這個(gè)引用變量就是一個(gè)強(qiáng)引用。當(dāng)一個(gè)對象被強(qiáng)引用變量引用時(shí),它處于可達(dá)狀態(tài),它是不可能被垃圾回收機(jī)制回收的,即
使該對象以后永遠(yuǎn)都不會被用到 JVM 也不會回收。軟引用,用SoftReference實(shí)現(xiàn),當(dāng)系統(tǒng)內(nèi)存足夠時(shí)它
不會被回收,當(dāng)系統(tǒng)內(nèi)存空間不足時(shí)它會被回收。軟引用通常用在對內(nèi)存敏感的程序中。弱引用,弱引用需要用 WeakReference 類來實(shí)現(xiàn),它比軟引用的生存期更短,對于只有弱引用的對象
來說,只要垃圾回收機(jī)制一運(yùn)行,不管 JVM 的內(nèi)存空間是否足夠,總會回收該對象占用的內(nèi)存。虛引用,虛引用需要 PhantomReference 類來實(shí)現(xiàn),它不能單獨(dú)使用,必須和引用隊(duì)列聯(lián)合使用。 虛
引用的主要作用是跟蹤對象被垃圾回收的狀態(tài)。
16. JAVA類加載機(jī)制?
JVM 類加載機(jī)制分為五個(gè)部分:加載,驗(yàn)證,準(zhǔn)備,解析,初始化。
加載, 這個(gè)階段會在內(nèi)存中生成一個(gè)代表這個(gè)類的 java.lang.Class 作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的入口。
驗(yàn)證,確保 Class文件的字節(jié)流中包含的信息是否符合當(dāng)前虛擬機(jī)的要求
準(zhǔn)備,是正式為類變量分配內(nèi)存并設(shè)置類變量的初始值階段,public static int v = 8080,實(shí)際上變量 v 在準(zhǔn)備階段過后的初始值為 0 而不是 8080,但是如果聲明的是常量就是8080,例如public static final int v = 8080。
解析,解析階段是指虛擬機(jī)將常量池中的符號引用替換為直接引用的過程。
17. 什么是雙親委派機(jī)制?
當(dāng)一個(gè)類收到了類加載請求,他首先不會嘗試自己去加載這個(gè)類,而是把這個(gè)請求委派給父
類去完成,每一個(gè)層次類加載器都是如此,因此所有的加載請求都應(yīng)該傳送到啟動類加載其中,
只有當(dāng)父類加載器反饋?zhàn)约簾o法完成這個(gè)請求的時(shí)候(在它的加載路徑下沒有找到所需加載的
Class), 子類加載器才會嘗試自己去加載。
18. CMS 收集器?
Concurrent mark sweep(CMS)收集器是一種年老代垃圾收集器,其最主要目標(biāo)是獲取最短垃圾 回收停頓時(shí)間,和其他年老代使用標(biāo)記-整理算法不同,它使用多線程的標(biāo)記-清除算法。 最短的垃圾收集停頓時(shí)間可以為交互比較高的程序提高用戶體驗(yàn)。 CMS工作機(jī)制相比其他的垃圾收集器來說更復(fù)雜,整個(gè)過程分為以下4個(gè)階段:
初始標(biāo)記 只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)的對象,速度很快,仍然需要暫停所有的工作線程。
并發(fā)標(biāo)記 進(jìn)行GC Roots跟蹤的過程,和用戶線程一起工作,不需要暫停工作線程。
重新標(biāo)記 為了修正在并發(fā)標(biāo)記期間,因用戶程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記 記錄,仍然需要暫停所有的工作線程。
并發(fā)清除 清除GC Roots不可達(dá)對象,和用戶線程一起工作,不需要暫停工作線程。由于耗時(shí)最長的并 發(fā)標(biāo)記和并發(fā)清除過程中,垃圾收集線程可以和用戶現(xiàn)在一起并發(fā)工作,所以總體上來看 CMS收集器的內(nèi)存回收和用戶線程是一起并發(fā)地執(zhí)行。
19. G1收集器?
Garbage first 垃圾收集器是目前垃圾收集器理論發(fā)展的最前沿成果,相比與CMS 收集器,G1 收 集器兩個(gè)最突出的改進(jìn)是:
- 基于標(biāo)記-整理算法,不產(chǎn)生內(nèi)存碎片。
- 可以非常精確控制停頓時(shí)間,在不犧牲吞吐量前提下,實(shí)現(xiàn)低停頓垃圾回收。 G1 收集器避免全區(qū)域垃圾收集,它把堆內(nèi)存劃分為大小固定的幾個(gè)獨(dú)立區(qū)域,并且跟蹤這些區(qū)域 的垃圾收集進(jìn)度,同時(shí)在后臺維護(hù)一個(gè)優(yōu)先級列表,每次根據(jù)所允許的收集時(shí)間,優(yōu)先回收垃圾 最多的區(qū)域。區(qū)域劃分和優(yōu)先級區(qū)域回收機(jī)制,確保 G1 收集器可以在有限時(shí)間獲得最高的垃圾收 集效率。