這是一份穩(wěn)收秋招offer的jvm常見(jiàn)面試題指南,助你成為offer收割機(jī)

JVM是java從業(yè)者,必須要邁過(guò)的坎,不管你是初級(jí)、中級(jí)還是高級(jí),都是必須掌握的,而且在面試中,jvm也是必考題,如果你不深入了解話(huà),那去面試找工作肯定是有點(diǎn)難受的。

本文將重點(diǎn)介紹面試過(guò)程中常見(jiàn)的 JVM 題目,將面試題分為三大類(lèi):基礎(chǔ)題目,進(jìn)階題目,實(shí)戰(zhàn)題目。

基礎(chǔ)

1.1 JDK、 JRE、JVM 的關(guān)系是什么?

什么是 JVM ?

英文名稱(chēng) ( Java Virtual Machine ),就是 JAVA 虛擬機(jī), 它只識(shí)別 .class 類(lèi)型文件,它能夠

將 class 文件中的字節(jié)碼指令進(jìn)行識(shí)別并調(diào)用操作系統(tǒng)向上的 API 完成動(dòng)作。

什么是 JRE ?

英文名稱(chēng)( Java Runtime Environment ),Java 運(yùn)行時(shí)環(huán)境。

它主要包含兩個(gè)部分:JVM 的標(biāo)準(zhǔn)實(shí)現(xiàn)和 Java 的一些基本類(lèi)庫(kù)。相對(duì)于 JVM 來(lái)說(shuō),JRE多出

來(lái)一部分 Java 類(lèi)庫(kù)。

什么是 JDK?

英文名稱(chēng)( Java Development Kit ),Java 開(kāi)發(fā)工具包。

JDK 是整個(gè) Java 開(kāi)發(fā)的核心,它集成了 JRE 和一些好用的小工具。

例如:javac.exe、java.exe、jar.exe 等。

這三者的關(guān)系:一層層的嵌套關(guān)系。JDK > JRE > JVM。

1.2 JVM 的內(nèi)存模型以及分區(qū)情況和作用

如下圖所示:

黃色部分為線(xiàn)程共有,藍(lán)色部分為線(xiàn)程私有。

方法區(qū)

用于存儲(chǔ)虛擬機(jī)加載的類(lèi)信息,常量,靜態(tài)變量等數(shù)據(jù)。

存放對(duì)象實(shí)例,所有的對(duì)象和數(shù)組都要在堆上分配。

是 JVM 所管理的內(nèi)存中最大的一塊區(qū)域。

Java 方法執(zhí)行的內(nèi)存模型:存儲(chǔ)局部變量表,操作數(shù)棧,動(dòng)態(tài)鏈接,方法出口等信息。

生命周期與線(xiàn)程相同。

本地方法棧

作用與虛擬機(jī)棧類(lèi)似,不同點(diǎn)本地方法棧為 native 方法執(zhí)行服務(wù),虛擬機(jī)棧為虛擬機(jī)執(zhí)行的

Java 方法服務(wù)。

程序計(jì)數(shù)器

當(dāng)前線(xiàn)程所執(zhí)行的行號(hào)指示器。是 JVM 內(nèi)存區(qū)域最小的一塊區(qū)域。執(zhí)行字節(jié)碼工作時(shí)就是利

用程序計(jì)數(shù)器來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令。

1.3 JVM 對(duì)象創(chuàng)建步驟流程是什么?

整體流程如下圖所示:

第 1 步:虛擬機(jī)遇到一個(gè) new 指令,首先將去檢查這個(gè)指令的參數(shù)是否能在常量池中定位到

這個(gè)類(lèi)的符號(hào)引用, 并且檢查這個(gè)符號(hào)引用的類(lèi)是否已經(jīng)被加載&解析&初始化。

第 2 步:如果類(lèi)已經(jīng)被加載那么進(jìn)行第 3 步; 如果沒(méi)有進(jìn)行加載, 那么就就需要先進(jìn)行類(lèi)的加載。

第 3 步:類(lèi)加載檢查通過(guò)之后, 接下來(lái)進(jìn)行新生對(duì)象的內(nèi)存分配。

第 4 步:對(duì)象生成需要的內(nèi)存大小在類(lèi)加載完成后便可完全確定,為對(duì)象分配空間等同于把一

塊確定大小的內(nèi)存從 Java 堆中劃分出來(lái)

第 5 步:內(nèi)存大小的劃分分為兩種情況:

第一種情況:JVM 的內(nèi)存是規(guī)整的, 所有的使用的內(nèi)存都放到一邊, 空閑的內(nèi)存在另外一

邊, 中間放一個(gè)指針作為分界點(diǎn)的指示器。 那么這時(shí)候分配內(nèi)存就比較簡(jiǎn)單, 只要講指針向

空閑空間那邊挪動(dòng)一段與對(duì)象大小相同的距離。 這種就是“指針碰撞”。

第二種情況:JVM 的內(nèi)存不是規(guī)整的, 也就是說(shuō)已使用的內(nèi)存與未使用的內(nèi)存相互交錯(cuò)。 這

時(shí)候就沒(méi)辦法利用指正碰撞了。 這時(shí)候我們就需要維護(hù)一張表,用于記錄那些內(nèi)存可用, 在

分配的時(shí)候從列表中找到一塊足夠大的空間劃分給對(duì)象實(shí)例, 并更新到記錄表上。

第 6 步:空間申請(qǐng)完成之后, JVM 需要將內(nèi)存的空間都初始化為 0 值。

如果使用 TLAB, 就可以在 TLAB 分配的時(shí)候就可以進(jìn)行該工作。

第 7 步: JVM 對(duì)對(duì)象進(jìn)行必要的設(shè)置。 例如, 這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例、對(duì)象的哈希碼、GC 年代等信息。

第 8 步:完成了上面的步驟之后 從 JVM 來(lái)看一個(gè)對(duì)象基本上完成了, 但從 Java 程序代碼絕對(duì)來(lái)看, 對(duì)象創(chuàng)建才剛剛開(kāi)始, 需要執(zhí)行 方法, 按照程序中設(shè)定的初始化操作初始化, 這時(shí)候一個(gè)真正的程序?qū)ο笊闪恕?/p>

1.4 垃圾回收算法有幾種類(lèi)型? 他們對(duì)應(yīng)的優(yōu)缺點(diǎn)又是什么?

常見(jiàn)的垃圾回收算法有:

標(biāo)記-清除算法

標(biāo)記—清除算法包括兩個(gè)階段:“標(biāo)記”和“清除”。

標(biāo)記階段:確定所有要回收的對(duì)象,并做標(biāo)記。

清除階段:將標(biāo)記階段確定不可用的對(duì)象清除。

缺點(diǎn):

1.標(biāo)記和清除的效率都不高。

2.會(huì)產(chǎn)生大量的碎片,而導(dǎo)致頻繁的回收。

復(fù)制算法

內(nèi)存分成大小相等的兩塊,每次使用其中一塊,當(dāng)垃圾回收的時(shí)候, 把存活的對(duì)象復(fù)制到另

一塊上,然后把這塊內(nèi)存整個(gè)清理掉。

缺點(diǎn):

1.需要浪費(fèi)額外的內(nèi)存作為復(fù)制區(qū)。

2.當(dāng)存活率較高時(shí),復(fù)制算法效率會(huì)下降。

標(biāo)記-整理算法

標(biāo)記—整理算法不是把存活對(duì)象復(fù)制到另一塊內(nèi)存,而是把存活對(duì)象往內(nèi)存的一端移動(dòng),然后

直接回收邊界以外的內(nèi)存。

缺點(diǎn): 算法復(fù)雜度大,執(zhí)行步驟較多.

分代收集算法

目前大部分 JVM 的垃圾收集器采用的算法。根據(jù)對(duì)象存活的生命周期將內(nèi)存劃分為若干個(gè)不同的區(qū)域。

一般情況將堆區(qū)劃分為新生代( Young Generation 和老年代( Tenured Generation ),永久代( Permanet Generation )。

老年代的特點(diǎn)是每次垃圾收集時(shí)只有少量對(duì)象需要被回收,而新生代的特點(diǎn)是每次垃圾回收時(shí)

都有大量的對(duì)象需要被回收,那么就可以根據(jù)不同代的特點(diǎn)采取最適合的收集算法。

如下圖所示:

Young:存放新創(chuàng)建的對(duì)象,對(duì)象生命周期非常短,幾乎用完可以立即回收,也叫 Eden 區(qū)。

Tenured: young 區(qū)多次回收后存活下來(lái)的對(duì)象將被移到 tenured 區(qū),也叫 old 區(qū)。

Perm:永久帶,主要存加載的類(lèi)信息,生命周期長(zhǎng),幾乎不會(huì)被回收。

缺點(diǎn): 算法復(fù)雜度大,執(zhí)行步驟較多。

1.5 簡(jiǎn)單介紹一下什么是類(lèi)加載機(jī)制?

Class 文件由類(lèi)裝載器裝載后,在 JVM 中將形成一份描述 Class 結(jié)構(gòu)的元信息對(duì)象,通過(guò)該

元信息對(duì)象可以獲知 Class 的結(jié)構(gòu)信息:如構(gòu)造函數(shù),屬性和方法等。

虛擬機(jī)把描述類(lèi)的數(shù)據(jù)從 class 文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),轉(zhuǎn)換解析和初始化,最

終形成可以被虛擬機(jī)直接使用的 Java 類(lèi)型,這就是虛擬機(jī)的類(lèi)加載機(jī)制。

1.6 類(lèi)的加載過(guò)程是什么?簡(jiǎn)單描述一下每個(gè)步驟:

類(lèi)加載的過(guò)程包括了:

第一步:加載

查找并加載類(lèi)的二進(jìn)制數(shù)據(jù)。

加載是類(lèi)加載過(guò)程的第一個(gè)階段,虛擬機(jī)在這一階段需要完成以下三件事情:

  • ·通過(guò)類(lèi)的全限定名來(lái)獲取其定義的二進(jìn)制字節(jié)流

  • 將字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)

  • 在 Java 堆中生成一個(gè)代表這個(gè)類(lèi)的 java.lang.Class 對(duì)象,作為對(duì)方法區(qū)中這些數(shù)據(jù)的訪問(wèn)入口

第二步:驗(yàn)證

確保被加載的類(lèi)的正確性。

這一階段是確保 Class 文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的規(guī)范,并且不會(huì)損害虛擬機(jī)自身的安全。

包含了四個(gè)驗(yàn)證動(dòng)作:文件格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證,字節(jié)碼驗(yàn)證,符號(hào)引用驗(yàn)證。

第三步:準(zhǔn)備

為類(lèi)的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值。

準(zhǔn)備階段是正式為類(lèi)變量分配內(nèi)存并設(shè)置類(lèi)變量初始值的階段,這些內(nèi)存都將在方法區(qū)中分配。

第四步:解析

把類(lèi)中的符號(hào)引用轉(zhuǎn)換為直接引用。

解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程,解析動(dòng)作主要針對(duì)類(lèi)或接

口、字段、類(lèi)方法、接口方法、方法類(lèi)型、方法句柄和調(diào)用點(diǎn)限定符 7 類(lèi)符號(hào)引用進(jìn)行。

第五步:初始化

類(lèi)變量進(jìn)行初始化

為類(lèi)的靜態(tài)變量賦予正確的初始值,JVM 負(fù)責(zé)對(duì)類(lèi)進(jìn)行初始化,主要對(duì)類(lèi)變量進(jìn)行初始化。

1.7 JVM 預(yù)定義的類(lèi)加載器有哪幾種?分別什么作用?

啟動(dòng)(Bootstrap)類(lèi)加載器、標(biāo)準(zhǔn)擴(kuò)展(Extension)類(lèi)加載器、應(yīng)用程序類(lèi)加載器(Application)

啟動(dòng)(Bootstrap)類(lèi)加載器

引導(dǎo)類(lèi)裝入器是用本地代碼實(shí)現(xiàn)的類(lèi)裝入器,它負(fù)責(zé)將 /lib 下面的類(lèi)庫(kù)加載到內(nèi)存中。

由于引導(dǎo)類(lèi)加載器涉及到虛擬機(jī)本地實(shí)現(xiàn)細(xì)節(jié),開(kāi)發(fā)者無(wú)法直接獲取到啟動(dòng)類(lèi)加載器的引用。

標(biāo)準(zhǔn)擴(kuò)展(Extension)類(lèi)加載器

擴(kuò)展類(lèi)加載器負(fù)責(zé)將 /lib/ext 或者由系統(tǒng)變量 java.ext.dir 指定位

置中的類(lèi)庫(kù)加載到內(nèi)存中。開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器。

應(yīng)用程序類(lèi)加載器(Application)

應(yīng)用程序類(lèi)加載器(Application ClassLoader):負(fù)責(zé)加載用戶(hù)路徑(classpath)上的類(lèi)庫(kù)。

1.8 什么是雙親委派模式?有什么作用?

基本定義:

雙親委派模型的工作流程是:如果一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求,它首先不會(huì)自己去加載

這個(gè)類(lèi),而是把請(qǐng)求委托給父加載器去完成,依次向上,因此,所有的類(lèi)加載請(qǐng)求最終都應(yīng)該

被傳遞到頂層的啟動(dòng)類(lèi)加載器中,只有當(dāng)父加載器沒(méi)有找到所需的類(lèi)時(shí),子加載器才會(huì)嘗試去

加載該類(lèi)。

雙親委派機(jī)制:

1.當(dāng) AppClassLoader 加載一個(gè) class 時(shí),它首先不會(huì)自己去嘗試加載這個(gè)類(lèi),而是把類(lèi)加載

請(qǐng)求委派給父類(lèi)加載器 ExtClassLoader 去完成。

2.當(dāng) ExtClassLoader 加載一個(gè) class 時(shí),它首先也不會(huì)自己去嘗試加載這個(gè)類(lèi),而是把類(lèi)加

載請(qǐng)求委派給 BootStrapClassLoader 去完成。

3.如果 BootStrapClassLoader 加載失敗,會(huì)使用 ExtClassLoader 來(lái)嘗試加載;

4.若 ExtClassLoader 也加載失敗,則會(huì)使用 AppClassLoader 來(lái)加載,如果

AppClassLoader 也加載失敗,則會(huì)報(bào)出異常 ClassNotFoundException。

雙親委派作用:

· 通過(guò)帶有優(yōu)先級(jí)的層級(jí)關(guān)可以避免類(lèi)的重復(fù)加載;

· 保證 Java 程序安全穩(wěn)定運(yùn)行,Java 核心 API 定義類(lèi)型不會(huì)被隨意替換。

1.9 介紹一下 JVM 中垃圾收集器有哪些? 他們特點(diǎn)分別是什么?

新生代垃圾收集器

Serial 收集器

特點(diǎn): Serial 收集器只能使用一條線(xiàn)程進(jìn)行垃圾收集工作,并且在進(jìn)行垃圾收集的時(shí)候,所有

的工作線(xiàn)程都需要停止工作,等待垃圾收集線(xiàn)程完成以后,其他線(xiàn)程才可以繼續(xù)工作。

使用算法:復(fù)制算法.

ParNew 收集器

特點(diǎn): ParNew 垃圾收集器是Serial收集器的多線(xiàn)程版本。為了利用 CPU 多核多線(xiàn)程的優(yōu)勢(shì),ParNew 收集器可以運(yùn)

行多個(gè)收集線(xiàn)程來(lái)進(jìn)行垃圾收集工作,這樣可以提高垃圾收集過(guò)程的效率。

使用算法:復(fù)制算法.

Parallel Scavenge 收集器

特點(diǎn): Parallel Scavenge 收集器是一款多線(xiàn)程的垃圾收集器,但是它又和 ParNew 有很大的不同點(diǎn)。

Parallel Scavenge 收集器和其他收集器的關(guān)注點(diǎn)不同。其他收集器,比如 ParNew 和 CMS

這些收集器,它們主要關(guān)注的是如何縮短垃圾收集的時(shí)間。

而 Parallel Scavenge 收集器關(guān)注的是如何控制系統(tǒng)運(yùn)行的吞吐量。這里說(shuō)的吞吐量,指的是

CPU 用于運(yùn)行應(yīng)用程序的時(shí)間和 CPU 總時(shí)間的占比,吞吐量 = 代碼運(yùn)行時(shí)間 / (代碼運(yùn)行

時(shí)間 + 垃圾收集時(shí)間)。如果虛擬機(jī)運(yùn)行的總的 CPU 時(shí)間是 100 分鐘,而用于執(zhí)行垃圾收
集的時(shí)間為 1 分鐘,那么吞吐量就是99%。

使用算法:復(fù)制算法

老年代垃圾收集器

Serial Old 收集器

特點(diǎn): Serial Old 收集器是 Serial 收集器的老年代版本。

這款收集器主要用于客戶(hù)端應(yīng)用程序中作為老年代的垃圾收集器,也可以作為服務(wù)端應(yīng)用程序的垃圾收集器。

使用算法:標(biāo)記-整理

Parallel Old 收集器

特點(diǎn): Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本這個(gè)收集器是在

JDK1.6 版本中出現(xiàn)的,所以在 JDK1.6 之前,新生代的 Parallel Scavenge 只能和 Serial Old

這款單線(xiàn)程的老年代收集器配合使用。Parallel Old 垃圾收集器和 Parallel Scavenge 收集器

一樣,也是一款關(guān)注吞吐量的垃圾收集器,和 Parallel Scavenge 收集器一起配合,可以實(shí)現(xiàn)

對(duì) Java 堆內(nèi)存的吞吐量?jī)?yōu)先的垃圾收集策略。

使用算法:標(biāo)記-整理

CMS 收集器

特點(diǎn): CMS 收集器是目前老年代收集器中比較優(yōu)秀的垃圾收集器。

CMS 是 Concurrent Mark Sweep,從名字可以看出,這是一款使用"標(biāo)記-清除"算法的并發(fā)收集器。

CMS 垃圾收集器是一款以獲取最短停頓時(shí)間為目標(biāo)的收集器。

從圖中可以看出,CMS 收集器的工作過(guò)程可以分為 4 個(gè)階段:

  • ·初始標(biāo)記(CMS initial mark)階段
  • 并發(fā)標(biāo)記(CMS concurrent mark)階段
  • ·重新標(biāo)記(CMS remark)階段
  • 并發(fā)清除((CMS concurrent sweep)階段

使用算法:復(fù)制+標(biāo)記清除

其他

G1 垃圾收集器

特點(diǎn): 主要步驟:初始標(biāo)記,并發(fā)標(biāo)記,重新標(biāo)記,復(fù)制清除

使用算法:復(fù)制 + 標(biāo)記整理

1.10 什么是 Class 文件? Class 文件主要的信息結(jié)構(gòu)有哪些?

Class 文件是一組以 8 位字節(jié)為基礎(chǔ)單位的二進(jìn)制流。各個(gè)數(shù)據(jù)項(xiàng)嚴(yán)格按順序排列。

Class 文件格式采用一種類(lèi)似于 C 語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)。

這樣的偽結(jié)構(gòu)僅僅有兩種數(shù)據(jù)類(lèi)型:無(wú)符號(hào)數(shù)和表。

無(wú)符號(hào)數(shù):是基本數(shù)據(jù)類(lèi)型。以 u1、u2、u4、u8 分別代表 1 個(gè)字節(jié)、2 個(gè)字節(jié)、4 個(gè)字

節(jié)、8 個(gè)字節(jié)的無(wú)符號(hào)數(shù),能夠用來(lái)描寫(xiě)敘述數(shù)字、索引引用、數(shù)量值或者依照 UTF-8 編碼

構(gòu)成的字符串值。

表:由多個(gè)無(wú)符號(hào)數(shù)或者其它表作為數(shù)據(jù)項(xiàng)構(gòu)成的復(fù)合數(shù)據(jù)類(lèi)型。全部表都習(xí)慣性地以 _info
結(jié)尾。

1.11 對(duì)象“對(duì)象已死” 是什么概念?

對(duì)象不可能再被任何途徑使用,稱(chēng)為對(duì)象已死。

判斷對(duì)象已死的方法有:引用計(jì)數(shù)法與可達(dá)性分析算法。

進(jìn)階

2.1 Java 語(yǔ)言怎么實(shí)現(xiàn)跨平臺(tái)的?

我們編寫(xiě)的 Java 源碼,編譯后會(huì)生成一種 .class 文件,稱(chēng)為字節(jié)碼文件。

字節(jié)碼不能直接運(yùn)行,必須通過(guò) JVM 翻譯成機(jī)器碼才能運(yùn)行。

JVM 是一個(gè)”橋梁“,是一個(gè)”中間件“,是實(shí)現(xiàn)跨平臺(tái)的關(guān)鍵。Java 代碼首先被編譯成字

節(jié)碼文件,再由 JVM 將字節(jié)碼文件翻譯成機(jī)器語(yǔ)言,從而達(dá)到運(yùn)行 Java 程序的目的。

2.2 JVM 數(shù)據(jù)運(yùn)行區(qū),哪些會(huì)造成 OOM 的情況?

除了數(shù)據(jù)運(yùn)行區(qū),其他區(qū)域均有可能造成 OOM 的情況。

2.3 詳細(xì)介紹一下對(duì)象在分帶內(nèi)存區(qū)域的分配過(guò)程?

JVM 會(huì)試圖為相關(guān) Java 對(duì)象在 Eden 中初始化一塊內(nèi)存區(qū)域。

當(dāng) Eden 空間足夠時(shí),內(nèi)存申請(qǐng)結(jié)束;否則到下一步。

JVM 試圖釋放在 Eden 中所有不活躍的對(duì)象(這屬于 1 或更高級(jí)的垃圾回收)。釋放后若

Eden 空間仍然不足以放入新對(duì)象,則試圖將部分 Eden 中活躍對(duì)象放入 Survivor 區(qū)。

Survivor 區(qū)被用來(lái)作為 Eden 及 Old 的中間交換區(qū)域,當(dāng) Old 區(qū)空間足夠時(shí),Survivor 區(qū)的

對(duì)象會(huì)被移到 Old 區(qū),否則會(huì)被保留在 Survivor 區(qū)。

當(dāng) Old 區(qū)空間不夠時(shí),JVM 會(huì)在 Old 區(qū)進(jìn)行完全的垃圾收集。

完全垃圾收集后,若 Survivor 及 Old 區(qū)仍然無(wú)法存放從 Eden 復(fù)制過(guò)來(lái)的部分對(duì)象,導(dǎo)致

JVM 無(wú)法在 Eden 區(qū)為新對(duì)象創(chuàng)建內(nèi)存區(qū)域,則出現(xiàn) “ out of memory ” 錯(cuò)誤。

1.4 G1 與 CMS 兩個(gè)垃圾收集器的對(duì)比

細(xì)節(jié)方面不同

1.G1 在壓縮空間方面有優(yōu)勢(shì)。

2.G1 通過(guò)將內(nèi)存空間分成區(qū)域(Region)的方式避免內(nèi)存碎片問(wèn)題。

3.Eden, Survivor, Old 區(qū)不再固定、在內(nèi)存使用效率上來(lái)說(shuō)更靈活。

4.G1 可以通過(guò)設(shè)置預(yù)期停頓時(shí)間(Pause Time)來(lái)控制垃圾收集時(shí)間避免應(yīng)用雪崩現(xiàn)象。

5.G1 在回收內(nèi)存后會(huì)馬上同時(shí)做合并空閑內(nèi)存的工作、而 CMS 默認(rèn)是在 STW(stop the world)的時(shí)候做。

6.G1 會(huì)在 Young GC 中使用、而 CMS 只能在 O 區(qū)使用。

整體內(nèi)容不同:

CMS 的缺點(diǎn)是對(duì) cpu 的要求比較高。

G1 是將內(nèi)存化成了多塊,所有對(duì)內(nèi)段的大小有很大的要求。

CMS 是清除,所以會(huì)存在很多的內(nèi)存碎片。

G1 是整理,所以碎片空間較小。

2.5 線(xiàn)上常用的 JVM 參數(shù)有哪些?

數(shù)據(jù)區(qū)設(shè)置

· Xms:初始堆大小

· Xmx:最大堆大小

· Xss:Java 每個(gè)線(xiàn)程的Stack大小

· XX:NewSize=n:設(shè)置年輕代大小

· XX:NewRatio=n:設(shè)置年輕代和年老代的比值。

如:為 3,表示年輕代與年老代比值為 1:3,年輕代占整個(gè)年輕代年老代和的 1/4。

· XX:SurvivorRatio=n:年輕代中 Eden 區(qū)與兩個(gè) Survivor 區(qū)的比值。

注意 Survivor 區(qū)有兩個(gè)。

如:3,表示 Eden:Survivor=3:2,一個(gè) Survivor 區(qū)占整個(gè)年輕代的 1/5。

· XX:MaxPermSize=n:設(shè)置持久代大小。

收集器設(shè)置

  • · XX:+UseSerialGC:設(shè)置串行收集器

  • · XX:+UseParallelGC::設(shè)置并行收集器

  • · XX:+UseParalledlOldGC:設(shè)置并行年老代收集器

  • · XX:+UseConcMarkSweepGC:設(shè)置并發(fā)收集器

GC日志打印設(shè)置

  • · XX:+PrintGC:打印 GC 的簡(jiǎn)要信息

  • · XX:+PrintGCDetails:打印 GC 詳細(xì)信息

  • · XX:+PrintGCTimeStamps:輸出 GC 的時(shí)間戳

2.6 對(duì)象什么時(shí)候進(jìn)入老年代?

對(duì)象優(yōu)先在 Eden 區(qū)分配內(nèi)存

當(dāng)對(duì)象首次創(chuàng)建時(shí), 會(huì)放在新生代的 eden 區(qū), 若沒(méi)有 GC 的介入,會(huì)一直在 eden 區(qū),GC

后,是可能進(jìn)入 survivor 區(qū)或者年老代

大對(duì)象直接進(jìn)入老年代

所謂的大對(duì)象是指需要大量連續(xù)內(nèi)存空間的 Java 對(duì)象,最典型的大對(duì)象就是那種很長(zhǎng)的字符

串以及數(shù)組,大對(duì)象對(duì)虛擬機(jī)的內(nèi)存分配就是壞消息,尤其是一些朝生夕滅的短命大對(duì)象,寫(xiě)

程序時(shí)應(yīng)避免。

長(zhǎng)期存活的對(duì)象進(jìn)入老年代

虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡(Age)計(jì)數(shù)器,對(duì)象在 Survivor 區(qū)中每熬過(guò)一次

Minor GC,年齡就增加 1,當(dāng)他的年齡增加到一定程度(默認(rèn)是 15 歲), 就將會(huì)被晉升到

老年代中。

2.7 什么是內(nèi)存溢出, 內(nèi)存泄露? 他們的區(qū)別是什么?

內(nèi)存溢出 out of memory,是指程序在申請(qǐng)內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory;

內(nèi)存泄露 memory leak,是指程序在申請(qǐng)內(nèi)存后,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄

露危害可以忽略,但內(nèi)存泄露堆積后果很?chē)?yán)重,無(wú)論多少內(nèi)存,遲早會(huì)被占光。

內(nèi)存溢出就是你要求分配的內(nèi)存超出了系統(tǒng)能給你的,系統(tǒng)不能滿(mǎn)足需求,于是產(chǎn)生溢出。

內(nèi)存泄漏是指你向系統(tǒng)申請(qǐng)分配內(nèi)存進(jìn)行使用(new),可是使用完了以后卻不歸還(delete),結(jié)果你申請(qǐng)到的那塊

內(nèi)存你自己也不能再訪問(wèn)(也許你把它的地址給弄丟了),而系統(tǒng)也不能再次將它分配給需要的程序。

2.8 引起類(lèi)加載操作的行為有哪些?

1.遇到 new、getstatic、putstatic 或 invokestatic 這四條字節(jié)碼指令。

2.反射調(diào)用的時(shí)候,如果類(lèi)沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。

3.子類(lèi)初始化的時(shí)候,如果其父類(lèi)還沒(méi)初始化,則需先觸發(fā)其父類(lèi)的初始化。

4.虛擬機(jī)執(zhí)行主類(lèi)的時(shí)候(有 main( string[] args))。

5.JDK1.7 動(dòng)態(tài)語(yǔ)言支持。

2.9 介紹一下 JVM 提供的常用工具

1.jps:用來(lái)顯示本地的 Java 進(jìn)程,可以查看本地運(yùn)行著幾個(gè) Java 程序,并顯示他們的進(jìn)程

號(hào)。

** 命令格式:jps.**

2.jinfo:運(yùn)行環(huán)境參數(shù):Java System 屬性和 JVM 命令行參數(shù),Java class path 等信息。

命令格式:jinfo 進(jìn)程 pid.

3.jstat:監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具。

** 命令格式:jstat -gc 123 250 20**

4.jstack:可以觀察到 JVM 中當(dāng)前所有線(xiàn)程的運(yùn)行情況和線(xiàn)程當(dāng)前狀態(tài)。

命令格式:jstack 進(jìn)程 pid.

5.jmap:觀察運(yùn)行中的 JVM 物理內(nèi)存的占用情況(如:產(chǎn)生哪些對(duì)象,及其數(shù)量)。

** 命令格式:jmap [option] pid.**

2.10 Full GC 、 Major GC 、Minor GC 之間區(qū)別?

Minor GC: 從新生代空間(包括 Eden 和 Survivor 區(qū)域)回收內(nèi)存被稱(chēng)為 Minor GC。

Major GC: 清理 Tenured 區(qū),用于回收老年代,出現(xiàn) Major GC 通常會(huì)出現(xiàn)至少一次 Minor GC。

Full GC: Full GC 是針對(duì)整個(gè)新生代、老年代、元空間(metaspace,java8 以上版本取代

perm gen)的全局范圍的 GC。

2.11 什么時(shí)候觸發(fā) Full GC ?

  1. 調(diào)用 System.gc 時(shí),系統(tǒng)建議執(zhí)行 Full GC,但是不必然執(zhí)行。

  2. 老年代空間不足。

  3. 方法區(qū)空間不足。

  4. 通過(guò) Minor GC 后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存。

  5. 由 Eden 區(qū)、survivor space1(From Space)區(qū)向 survivor space2(To Space)區(qū)復(fù)制時(shí),對(duì)象大小大于 To

Space 可用內(nèi)存,則把該對(duì)象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對(duì)象大小。

6. 2.12 什么情況下會(huì)出現(xiàn)棧溢出

1.方法創(chuàng)建了一個(gè)很大的對(duì)象,如 List,Array。

2.是否產(chǎn)生了循環(huán)調(diào)用、死循環(huán)。

3.是否引用了較大的全局變量。

2.13 說(shuō)一下強(qiáng)引用、軟引用、弱引用、虛引用以及他們之間和 gc 的關(guān)系

1.強(qiáng)引用:new 出的對(duì)象之類(lèi)的引用,只要強(qiáng)引用還在,永遠(yuǎn)不會(huì)回收。

2.軟引用:引用但非必須的對(duì)象,內(nèi)存溢出異常之前,回收。

3.弱引用:非必須的對(duì)象,對(duì)象能生存到下一次垃圾收集發(fā)生之前。

4.虛引用:對(duì)生存時(shí)間無(wú)影響,在垃圾回收時(shí)得到通知。

2.14 Eden 和 Survivor 的比例分配是什么情況?為什么?

默認(rèn)比例 8:1。 大部分對(duì)象都是朝生夕死。

復(fù)制算法的基本思想就是將內(nèi)存分為兩塊,每次只用其中一塊,當(dāng)這一塊內(nèi)存用完,就將還活

著的對(duì)象復(fù)制到另外一塊上面。復(fù)制算法不會(huì)產(chǎn)生內(nèi)存碎片。

實(shí)戰(zhàn)

3.1 CPU 資源占用過(guò)高

1.top 查看當(dāng)前 CPU 情況,找到占用 CPU 過(guò)高的進(jìn)程 PID=123。

2.top -H -p123 找出兩個(gè) CPU 占用較高的線(xiàn)程,記錄下來(lái) PID=2345, 3456 轉(zhuǎn)換為十六進(jìn)制。

3.jstack -l 123 > temp.txt 打印出當(dāng)前進(jìn)程的線(xiàn)程棧。

4.查找到對(duì)應(yīng)于第二步的兩個(gè)線(xiàn)程運(yùn)行棧,分析代碼。

3.2 OOM 異常排查

1.使用 top 指令查詢(xún)服務(wù)器系統(tǒng)狀態(tài)。

2.ps -aux|grep java 找出當(dāng)前 Java 進(jìn)程的 PID。

3.jstat -gcutil pid interval 查看當(dāng)前 GC 的狀態(tài)。

4.jmap -histo:live pid 可用統(tǒng)計(jì)存活對(duì)象的分布情況,從高到低查看占據(jù)內(nèi)存最多的對(duì)象。

5.jmap -dump:format=b,file= 文件名 [pid] 利用 Jmap dump。

6.使用性能分析工具對(duì)上一步 dump 出來(lái)的文件進(jìn)行分析,工具有 MAT 等。

上面介紹了 JVM 常見(jiàn)的面試題目,希望對(duì)大家接下來(lái)的面試或者對(duì)于 JVM 的深入學(xué)習(xí)有所幫助。

除了上面的jvm知識(shí)點(diǎn),還收集了各方面的,當(dāng)前公司的,還有自己收集總結(jié)的,下面的圖片截取的有pdf,有如果有需要的自取.

各大公司面試題集合:

image

簡(jiǎn)歷模板:
image

鏈接: https://pan.baidu.com/s/1DO6XGkbmak7KIt6Y7JQqyw
提取碼:fgj6
不知道會(huì)不會(huì)失效,如果失效點(diǎn)擊(778490892)或者掃描下面二維碼,進(jìn)群獲取,鏈接補(bǔ)發(fā)不過(guò)來(lái),謝謝。
在這里插入圖片描述

最后

歡迎大家評(píng)論區(qū)一起交流,相互提升;整理資料不易,如果喜歡文章記得點(diǎn)個(gè)贊哈,感謝大家支持?。。?/strong>

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

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