您好,歡迎來(lái)到賦能網(wǎng)!

JVM相關(guān)技術(shù)面試題匯總

賦能網(wǎng) 2023-06-10 230

1 JVM內(nèi)存分哪幾個(gè)區(qū),每個(gè)區(qū)的作用是什么?

 

java虛擬機(jī)主要分為以下幾個(gè)區(qū):

(1)方法區(qū)

  • a. JDK7中稱為永久代,JDK8及之后稱為元空間,在該區(qū)內(nèi)很少發(fā)生垃圾回收,但是并不代表不發(fā)生GC,在這里進(jìn)行的GC主要是對(duì)方法區(qū)里的常量池和對(duì)類型的卸載
  • b. 方法區(qū)主要用來(lái)存儲(chǔ)已被虛擬機(jī)加載的類的信息、常量、靜態(tài)變量和即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
  • c. 該區(qū)域是被線程共享的。
  • d. 方法區(qū)里有一個(gè)運(yùn)行時(shí)常量池,用于存放靜態(tài)編譯產(chǎn)生的字面量和符號(hào)引用。該常量池具有動(dòng)態(tài)性,也就是說(shuō)常量并不一定是編譯時(shí)確定,運(yùn)行時(shí)生成的常量也會(huì)存在這個(gè)常量池中。

(2)虛擬機(jī)棧:

  • a. 虛擬機(jī)棧也就是我們平常所稱的棧內(nèi)存,它為java方法服務(wù),每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀,用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接和方法出口等信息。
  • b. 虛擬機(jī)棧是線程私有的,它的生命周期與線程相同。
  • c. 局部變量表里存儲(chǔ)的是基本數(shù)據(jù)類型、returnAddress類型(指向一條字節(jié)碼指令的地址)和對(duì)象引用,這個(gè)對(duì)象引用有可能是指向?qū)ο笃鹗嫉刂返囊粋€(gè)指針,也有可能是代表對(duì)象的句柄或者與對(duì)象相關(guān)聯(lián)的位置。局部變量所需的內(nèi)存空間在編譯器間確定
  • d. 操作數(shù)棧的作用主要用來(lái)存儲(chǔ)運(yùn)算結(jié)果以及運(yùn)算的操作數(shù),它不同于局部變量表通過(guò)索引來(lái)訪問(wèn),而是壓棧和出棧的方式
  • e. 每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用,持有這個(gè)引用是為了支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接.動(dòng)態(tài)鏈接就是將常量池中的符號(hào)引用在運(yùn)行期轉(zhuǎn)化為直接引用。

(3)本地方法棧

本地方法棧和虛擬機(jī)棧類似,只不過(guò)本地方法棧為Native方法服務(wù)。

(4)堆

java堆是所有線程所共享的一塊內(nèi)存,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,幾乎所有的對(duì)象實(shí)例都在這里創(chuàng)建,因此該區(qū)域經(jīng)常發(fā)生垃圾回收操作。

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

內(nèi)存空間小,字節(jié)碼解釋器工作時(shí)通過(guò)改變這個(gè)計(jì)數(shù)值可以選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理和線程恢復(fù)等功能都需要依賴這個(gè)計(jì)數(shù)器完成。該內(nèi)存區(qū)域是唯一一個(gè)java虛擬機(jī)規(guī)范沒(méi)有規(guī)定任何OOM情況的區(qū)域。

2 heap 和stack 有什么區(qū)別

(1)申請(qǐng)方式

stack:由系統(tǒng)自動(dòng)分配。例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為 b 開(kāi)辟空間

heap:需要程序員自己申請(qǐng),并指明大小,在 c 中 malloc 函數(shù),對(duì)于Java 需要手動(dòng) new Object()的形式開(kāi)辟

(2)申請(qǐng)后系統(tǒng)的響應(yīng)

stack:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。

heap:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí),會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)地將多余的那部分重新放入空閑鏈表中。

(3)申請(qǐng)大小的限制

stack:棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS 下,棧的大小是 2M(默認(rèn)值也取決于虛擬內(nèi)存的大?。绻暾?qǐng)的空間超過(guò)棧的剩余空間時(shí),將提示 overflow。因此,能從棧獲得的空間較小。

heap:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來(lái)存儲(chǔ)的空閑內(nèi)存地址的, 自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見(jiàn), 堆獲得的空間比較靈活,也比較大。

(4)申請(qǐng)效率的比較

stack:由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無(wú)法控制的。

heap:由 new 分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便。

(5)heap和stack中的存儲(chǔ)內(nèi)容

stack:在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的地址, 然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的 C 編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。

當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開(kāi)始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。

heap:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容由程序員安排。

3 java類加載過(guò)程?

Java類加載需要經(jīng)歷一下幾個(gè)過(guò)程:

(1)加載

加載時(shí)類加載的第一個(gè)過(guò)程,在這個(gè)階段,將完成一下三件事情:

  1. a. 通過(guò)一個(gè)類的全限定名獲取該類的二進(jìn)制流。
  2. b. 將該二進(jìn)制流中的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法去運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
  3. c. 在內(nèi)存中生成該類的Class對(duì)象,作為該類的數(shù)據(jù)訪問(wèn)入口。

(2)鏈接

2.1)驗(yàn)證

驗(yàn)證的目的是為了確保Class文件的字節(jié)流中的信息不會(huì)危害到虛擬機(jī).在該階段主要完成以下四鐘驗(yàn)證:

  • a. 文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件的規(guī)范,如主次版本號(hào)是否在當(dāng)前虛擬機(jī)范圍內(nèi),常量池中的常量是否有不被支持的類型.
  • b. 元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,如這個(gè)類是否有父類,是否繼承了不被繼承的類等。
  • c. 字節(jié)碼驗(yàn)證:是整個(gè)驗(yàn)證過(guò)程中最復(fù)雜的一個(gè)階段,通過(guò)驗(yàn)證數(shù)據(jù)流和控制流的分析,確定程序語(yǔ)義是否正確,主要針對(duì)方法體的驗(yàn)證。如:方法中的類型轉(zhuǎn)換是否正確,跳轉(zhuǎn)指令是否正確等。
  • d. 符號(hào)引用驗(yàn)證:這個(gè)動(dòng)作在后面的解析過(guò)程中發(fā)生,主要是為了確保解析動(dòng)作能正確執(zhí)行。

2.2)準(zhǔn)備

準(zhǔn)備階段是為類的靜態(tài)變量分配內(nèi)存并將其初始化為默認(rèn)值,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配。準(zhǔn)備階段不分配類中的實(shí)例變量的內(nèi)存,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在Java堆中。

2.3)解析

該階段主要完成符號(hào)引用到直接引用的轉(zhuǎn)換動(dòng)作。解析動(dòng)作并不一定在初始化動(dòng)作完成之前,也有可能在初始化之后。

(3)初始化 初始化時(shí)類加載的最后一步,前面的類加載過(guò)程,除了在加載階段用戶應(yīng)用程序可以通過(guò)自定義類加載器參與之外,其余動(dòng)作完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段,才真正開(kāi)始執(zhí)行類中定義的Java程序代碼。

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

實(shí)現(xiàn)通過(guò)類的全限定名獲取該類的二進(jìn)制字節(jié)流的代碼塊叫做類加載器。

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

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

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

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

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

5 java中垃圾收集的方法有哪些?

1)引用計(jì)數(shù)法算法 應(yīng)用于:微軟的COM/ActionScrip3/Python等

a) 如果對(duì)象沒(méi)有被引用,就會(huì)被回收,缺點(diǎn):需要維護(hù)一個(gè)引用計(jì)算器

2)可達(dá)性分析算法 以根對(duì)象集合(GC Roots)為起始點(diǎn),按照從上至下的方式搜索被根對(duì)象集合所連接的目標(biāo)對(duì)象是否可達(dá)。不可達(dá)的,就意味著該對(duì)象已經(jīng)死亡,可以標(biāo)記為垃圾對(duì)象。

3)復(fù)制算法 年輕代中使用的是Minor GC,這種GC算法采用的是復(fù)制算法(Copying)

a) 效率高,缺點(diǎn):需要內(nèi)存容量大,比較耗內(nèi)存

b) 使用在占空間比較小、刷新次數(shù)多的新生區(qū)

4)標(biāo)記-清除算法 老年代一般是由標(biāo)記清除或者是標(biāo)記清除與標(biāo)記整理的混合實(shí)現(xiàn)

a) 效率比較低,會(huì)產(chǎn)生碎片。

5)標(biāo)記-壓縮算法 老年代一般是由標(biāo)記清除或者是標(biāo)記清除與標(biāo)記整理的混合實(shí)現(xiàn)

a) 效率低速度慢,需要移動(dòng)對(duì)象,但不會(huì)產(chǎn)生碎片。

6)標(biāo)記-清除-壓縮算法 標(biāo)記清除-標(biāo)記壓縮的集合,多次GC后才Compact

a) 適用于占空間大刷新次數(shù)少的養(yǎng)老區(qū),是4)和5)的集合體

6 如何判斷一個(gè)對(duì)象是否存活?(或者GC對(duì)象的判定方法)

判斷一個(gè)對(duì)象是否存活有兩種方法:

(1)引用計(jì)數(shù)法

所謂引用計(jì)數(shù)法就是給每一個(gè)對(duì)象設(shè)置一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用這個(gè)對(duì)象時(shí),就將計(jì)數(shù)器加一,引用失效時(shí),計(jì)數(shù)器就減一。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器為零時(shí),說(shuō)明此對(duì)象沒(méi)有被引用,也就是“死對(duì)象”,將會(huì)被垃圾回收.

引用計(jì)數(shù)法有一個(gè)缺陷就是無(wú)法解決循環(huán)引用問(wèn)題,也就是說(shuō)當(dāng)對(duì)象A引用對(duì)象B,對(duì)象B又引用者對(duì)象A,那么此時(shí)A,B對(duì)象的引用計(jì)數(shù)器都不為零,也就造成無(wú)法完成垃圾回收,所以主流的虛擬機(jī)都沒(méi)有采用這種算法。

(2)可達(dá)性算法(引用鏈法)

該算法的基本思路就是通過(guò)以GC Roots對(duì)象作為起點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索走過(guò)的路徑被稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)(即從GC Roots節(jié)點(diǎn)到該節(jié)點(diǎn)不可達(dá)),則證明該對(duì)象是不可用的。

在java中可以作為GC Roots的對(duì)象有以下幾種:虛擬機(jī)棧中引用的對(duì)象、方法區(qū)類靜態(tài)屬性引用的對(duì)象、方法區(qū)常量池引用的對(duì)象、本地方法棧JNI引用的對(duì)象。

JVM相關(guān)技術(shù)面試題匯總

7 簡(jiǎn)述java內(nèi)存分配與回收策略以及Minor GC和Major GC(full GC)

內(nèi)存分配:

(1)棧區(qū):棧分為java虛擬機(jī)棧和本地方法棧

(2)堆區(qū):堆被所有線程共享區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,唯一目的存放對(duì)象實(shí)例。堆區(qū)是gc的主要區(qū)域,通常情況下分為兩個(gè)區(qū)塊年輕代和年老代。更細(xì)一點(diǎn)年輕代又分為Eden區(qū),主要放新創(chuàng)建對(duì)象,F(xiàn)rom survivor 和 To survivor 保存gc后幸存下的對(duì)象,默認(rèn)情況下各自占比 8:1:1。

(3)方法區(qū):被所有線程共享區(qū)域,用于存放已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量等數(shù)據(jù)。被Java虛擬機(jī)描述為堆的一個(gè)邏輯部分。習(xí)慣上也叫它永久代(permanment generation)

(4)程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的信號(hào)指示器。通過(guò)改變計(jì)數(shù)器的值來(lái)確定下一條指令,比如循環(huán),分支,跳轉(zhuǎn),異常處理,線程恢復(fù)等都是依賴計(jì)數(shù)器來(lái)完成。線程私有的。

回收策略以及Minor GC和Major GC:

(1)對(duì)象優(yōu)先在堆的Eden區(qū)分配。

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

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

當(dāng)Eden區(qū)沒(méi)有足夠的空間進(jìn)行分配時(shí),虛擬機(jī)會(huì)執(zhí)行一次Minor GC.Minor GC通常發(fā)生在新生代的Eden區(qū),在這個(gè)區(qū)的對(duì)象生存期短,往往發(fā)生GC的頻率較高,回收速度比較快;Full Gc/Major GC 發(fā)生在老年代,一般情況下,觸發(fā)老年代GC的時(shí)候不會(huì)觸發(fā)Minor GC,但是通過(guò)配置,可以在Full GC之前進(jìn)行一次Minor GC這樣可以加快老年代的回收速度。

本文鏈接:

本文章“JVM相關(guān)技術(shù)面試題匯總”已幫助 230 人

免責(zé)聲明:本信息由用戶發(fā)布,本站不承擔(dān)本信息引起的任何交易及知識(shí)產(chǎn)權(quán)侵權(quán)的法律責(zé)任!

本文由賦能網(wǎng) 整理發(fā)布。了解更多培訓(xùn)機(jī)構(gòu)》培訓(xùn)課程》學(xué)習(xí)資訊》課程優(yōu)惠》課程開(kāi)班》學(xué)校地址等機(jī)構(gòu)信息,可以留下您的聯(lián)系方式,讓課程老師跟你詳細(xì)解答:
咨詢熱線:4008-569-579

如果本頁(yè)不是您要找的課程,您也可以百度查找一下: