2020年JVM高頻率面試題整理

1、內存模型以及分區(qū),需要詳細到每個區(qū)放什么。
JVM 分為堆區(qū)和棧區(qū),還有方法區(qū),初始化的對象放在堆里面,引用放在棧里面, class 類信息常量池(static 常量和 static 變量)等放在方法區(qū) new: 方法區(qū):主要是存儲類信息,常量池(static 常量和 static 變量),編譯后的代碼(字節(jié)碼)等數據 堆:初始化的對象,成員變量 (那種非 static 的變量),所有的對象實例和數組都要在堆上分配
棧:棧的結構是棧幀組成的,調用一個方法就壓入一幀,幀上面存儲局部變量表,操作數棧,方法出口等信息,局部變量表存放的是 8 大基礎類型加上一個應用類型,所以還是一個指向地址的指針 本地方法棧:主要為 Native 方法服務 程序計數器:記錄當前線程執(zhí)行的行號
2. 堆里面的分區(qū):Eden,survival (from+ to),老年代,各自的特點。
堆里面分為新生代和老生代(java8 取消了永久代,采用了 Metaspace),新生代包 含 Eden+Survivor 區(qū),survivor 區(qū)里面分為 from 和 to 區(qū),內存回收時,如果用的是復制算法,從 from 復制到 to,當經過一次或者多次 GC 之后,存活下來的對象會被移動到老年區(qū),當 JVM 內存不夠用的時候,會觸發(fā) Full GC,清理 JVM 老年區(qū)當新生區(qū)滿了之后會觸發(fā) YGC,先把存活的對象放到其中一個 Survice 區(qū),然后進行垃圾清理。因為如果僅僅清理需要刪除的對象,這樣會導致內存碎片,因此一般會把 Eden 進行完全的清理,然后整理內存。那么下次 GC 的時候, 就會使用下一個 Survive,這樣循環(huán)使用。如果有特別大的對象,新生代放不下,就會使用老年代的擔保,直接放到老年代里面。因為 JVM 認為,一般大對象的存 活時間一般比較久遠。
3. 對象創(chuàng)建方法,對象的內存分配,對象的訪問定位。
new 一個對象
4. GC 的兩種判定方法:
引用計數法:指的是如果某個地方引用了這個對象就+1,如果失效了就-1,當為 0 就
會回收但是 JVM 沒有用這種方式,因為無法判定相互循環(huán)引用(A 引用 B,B 引用 A) 的情況
引用鏈法: 通過一種 GC ROOT 的對象(方法區(qū)中靜態(tài)變量引用的對象等-static 變量)來判斷,如果有一條鏈能夠到達 GC ROOT 就說明,不能到達 GC ROOT 就說明
可以回收
5. SafePoint 是什么
比如 GC 的時候必須要等到 Java 線程都進入到 safepoint 的時候 VMThread 才能開始執(zhí)行 GC
循環(huán)的末尾 (防止大循環(huán)的時候一直不進入 safepoint,而其他線程在等待它進入 safepoint)
- 方法返回前
- 調用方法的 call 之后
- 拋出異常的位置
6. GC 的三種收集方法:標記清除、標記整理、復制算法的原理與特點,分別用
在什么地方,如果讓你優(yōu)化收集方法,有什么思路?先標記,標記完畢之后再清除,效率不高,會產生碎片復制算法:分為 8:1 的 Eden 區(qū)和 survivor 區(qū),就是上面談到的 YGC標記整理:標記完畢之后,讓所有存活的對象向一端移動
7. GC 收集器有哪些?CMS 收集器與 G1 收集器的特點。
并行收集器:串行收集器使用一個單獨的線程進行收集,GC 時服務有停頓時間串行收集器:次要回收中使用多線程來執(zhí)行
CMS 收集器是基于“標記清除”算法實現的,經過多次標記才會被清除
G1 從**整體來看是基于****“標記—整理”算法實現的收集器,從局部(兩個 Region 之間上來看是基于“復制”算法實現的
8. Minor GC 與 Full GC 分別在什么時候發(fā)生?
新生代內存不夠用時候發(fā)生 MGC 也叫 YGC,JVM 內存不夠的時候發(fā)生 FGC
9. 幾種常用的內存調試工具:jmap、jstack、jconsole、jhat
jstack 可以看當前棧的情況,jmap 查看內存,jhat 進行 dump 堆的信息
mat(eclipse 的也要了解一下)
10. 類加載的幾個過程:
加載、驗證、準備、解析、初始化。然后是使用和卸載了
通過全限定名來加載生成 class 對象到內存中,然后進行驗證這個 class 文件,包括文件格式校驗、元數據驗證,字節(jié)碼校驗等。準備是對這個對象分配內存。解析是將符
號引用轉化為直接引用(指針引用),初始化就是開始執(zhí)行構造器的代碼
**11.JVM 內存分哪幾個區(qū),每個區(qū)的作用是什么? ** java 虛擬機主要分為以下一個區(qū):
方法區(qū):
- 有時候也成為永久代,在該區(qū)內很少發(fā)生垃圾回收,但是并不代表不發(fā)生 GC,在這里進行的 GC 主要是對方法區(qū)里的常量池和對類型的卸載
- 方法區(qū)主要用來存儲已被虛擬機加載的類的信息、常量、靜態(tài)變量和即時編譯器編譯后的代碼等數據。
- 該區(qū)域是被線程共享的。
- 方法區(qū)里有一個運行時常量池,用于存放靜態(tài)編譯產生的字面量和符號引用。該常量池具有動態(tài)性,也就是說常量并不一定是編譯時確定,運行時生成的常量也會存在這個常量池中。
虛擬機棧:
- 虛擬機棧也就是我們平常所稱的棧內存,它為 java 方法服務,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀,用于存儲局部變量表、操作數棧、動態(tài)鏈接和方法出口等信息。
- 虛擬機棧是線程私有的,它的生命周期與線程相同。
- 局部變量表里存儲的是基本數據類型、returnAddress 類型(指向一條字節(jié)碼指令的地址)和對象引用,這個對象引用有可能是指向對象起始地址的一個指針,也有可能是代表對象的句柄或者與對象相關聯的位置。局部變量所需的內存空間在編譯器間確定
4.操作數棧的作用主要用來存儲運算結果以及運算的操作數,它不同于局部變量表通過索
引來訪問,而是壓棧和出棧的方式
5.每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了
支持方法調用過程中的動態(tài)連接.動態(tài)鏈接就是將常量池中的符號引用在運行期轉化為直接
引用。
本地方法棧
本地方法棧和虛擬機棧類似,只不過本地方法棧為 Native 方法服務。
堆
java 堆是所有線程所共享的一塊內存,在虛擬機啟動時創(chuàng)建,幾乎所有的對象實例都在這里創(chuàng)建,因此該區(qū)域經常發(fā)生垃圾回收操作。
程序計數器
- 內存空間小,字節(jié)碼解釋器工作時通過改變這個計數值可以選取下一條需要執(zhí)行的字節(jié)碼
- 指令,分支、循環(huán)、跳轉、異常處理和線程恢復等功能都需要依賴這個計數器完成。該內
- 存區(qū)域是唯一一個 java 虛擬機規(guī)范沒有規(guī)定任何 OOM 情況的區(qū)域。
12.如和判斷一個對象是否存活?(或者 GC 對象的判定方法
判斷一個對象是否存活有兩種方法:
引用計數法
所謂引用計數法就是給每一個對象設置一個引用計數器,每當有一個地方引用這個對象時,就將計數器加一,引用失效時,計數器就減一。當一個對象的引用計數器為零時,說明此對象沒有被引用,也就是“死對象”,將會被垃圾回收.
引用計數法有一個缺陷就是無法解決循環(huán)引用問題,也就是說當對象 A 引用對象 B,對象
B 又引用者對象 A,那么此時 A,B 對象的引用計數器都不為零,也就造成無法完成垃圾回收,所以主流的虛擬機都沒有采用這種算法。
2.可達性算法(引用鏈法)
該算法的思想是:從一個被稱為 GC Roots的對象開始向下搜索,如果一個對象到 GC
Roots 沒有任何引用鏈相連時,則說明此對象不可用。
在 java 中可以作為 GC Roots 的對象有以下幾種:
- 虛擬機棧中引用的對象
- 方法區(qū)類靜態(tài)屬性引用的對象
- 方法區(qū)常量池引用的對象
- 本地方法棧 JNI 引用的對象
雖然這些算法可以判定一個對象是否能被回收,但是當滿足上述條件時,一個對象比不一定會被回收。當一個對象不可達 GC Root 時,這個對象并不會立馬被回收,而是出于一個死緩的階段,若要被真正的回收需要經歷兩次標記
如果對象在可達性分析中沒有與 GC Root 的引用鏈,那么此時就會被第一次標記并且進行一次篩選,篩選的條件是是否有必要執(zhí)行 finalize()方法。當對象沒有覆蓋 finalize()方法或者已被虛擬機調用過,那么就認為是沒必要的。
如果該對象有必要執(zhí)行 finalize()方法,那么這個對象將會放在一個稱為 F-Queue 的對隊列中,虛擬機會觸發(fā)一個 Finalize()線程去執(zhí)行,此線程是低優(yōu)先級的,并且虛擬機不會承
諾一直等待它運行完,這是因為如果 finalize()執(zhí)行緩慢或者發(fā)生了死鎖,那么就會造成 FQueue 隊列一直等待,造成了內存回收系統的崩潰。GC 對處于 F-Queue 中的對象進行第二次被標記,這時,該對象將被移除”即將回收”集合,等待回收。
13.簡述 java 垃圾回收機制?
在 java 中,程序員是不需要顯示的去釋放一個對象的內存的,而是由虛擬機自行執(zhí)行。在JVM 中,有一個垃圾回收線程,它是低優(yōu)先級的,在正常情況下是不會執(zhí)行的,只有在虛擬機空閑或者當前堆內存不足時,才會觸發(fā)執(zhí)行,掃面那些沒有被任何引用的對象,并將它們添加到要回收的集合中,進行回收。
14.java 中垃圾收集的方法有哪些?
標記-清除: 這是垃圾收集算法中最基礎的,根據名字就可以知道,它的思想就是標記哪些要被回收的對象,然后統一回收。這種方法很簡單,但是會有兩個主要問題:1.效率不高,標記和清除的效率都很低;2.會產生大量不連續(xù)的內存碎片,導致以后程序在分配較大的對象時,由于沒有充足的連續(xù)內存而提前觸發(fā)一次 GC 動作。
復制算法: 為了解決效率問題,復制算法將可用內存按容量劃分為相等的兩部分,然后每次只使用其中的一塊,當一塊內存用完時,就將還存活的對象復制到第二塊內存上,然
后一次性清楚完第一塊內存,再將第二塊上的對象復制到第一塊。但是這種方式,內存的代價太高,每次基本上都要浪費一般的內存。
于是將該算法進行了改進,內存區(qū)域不再是按照 1:1 去劃分,而是將內存劃分為8:1:1 三部分,較大那份內存交 Eden 區(qū),其余是兩塊較小的內存區(qū)叫 Survior 區(qū)。
每次都會優(yōu)先使用 Eden 區(qū),若 Eden 區(qū)滿,就將對象復制到第二塊內存區(qū)上,然
后清除 Eden 區(qū),如果此時存活的對象太多,以至于 Survivor 不夠時,會將這些對象通過分配擔保機制復制到老年代中。(java 堆又分為新生代和老年代)
標記-整理該算法主要是為了解決標記-清除,產生大量內存碎片的問題;當對象存活率較高時,也解決了復制算法的效率問題。它的不同之處就是在清除對象的時候現將可回
收對象移動到一端,然后清除掉端邊界以外的對象,這樣就不會產生內存碎片了。
分代收集現在的虛擬機垃圾收集大多采用這種方式,它根據對象的生存周期,將堆分為新生代和老年代。在新生代中,由于對象生存期短,每次回收都會有大量對象死去,那么這時就采用復制算法。老年代里的對象存活率較高,沒有額外的空間進行分配擔保,所以可以使用標記-整理或者 標記-清除。
15.java 內存模型
java 內存模型(JMM)是線程間通信的控制機制.JMM 定義了主內存和線程之間抽象關系。
線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是
JMM 的一個抽象概念,并不真實存在。它涵蓋了緩存,寫緩沖區(qū),寄存器以及其他的硬件和編譯器優(yōu)化。Java 內存模型的抽象示意圖如下:從上圖來看,線程 A 與線程 B 之間如要通信的話,必須要經歷下面 2 個步驟:
首先,線程 A 把本地內存 A 中更新過的共享變量刷新到主內存中去。然后,線程 B 到主內存中去讀取線程 A 之前已更新過的共享變量。
16.java 類加載過程?
java 類加載需要經歷一下 7 個過程:
加載
加載時類加載的第一個過程,在這個階段,將完成一下三件事情:
- 通過一個類的全限定名獲取該類的二進制流。
- 將該二進制流中的靜態(tài)存儲結構轉化為方法去運行時數據結構。
- 在內存中生成該類的 Class 對象,作為該類的數據訪問入口。
驗證
驗證的目的是為了確保 Class 文件的字節(jié)流中的信息不回危害到虛擬機.在該階段主要完成
以下四鐘驗證:
文件格式驗證:驗證字節(jié)流是否符合 Class 文件的規(guī)范,如主次版本號是否在當前虛擬機范圍內,常量池中的常量是否有不被支持的類型.
元數據驗證:對字節(jié)碼描述的信息進行語義分析,如這個類是否有父類,是否集成了不被繼承的類等。
字節(jié)碼驗證:是整個驗證過程中最復雜的一個階段,通過驗證數據流和控制流的分析,確定程序語義是否正確,主要針對方法體的驗證。如:方法中的類型轉換是否正確,跳轉
指令是否正確等。4. 符號引用驗證:這個動作在后面的解析過程中發(fā)生,主要是為了確保解析動作能正確執(zhí)
行。
準備
準備階段是為類的靜態(tài)變量分配內存并將其初始化為默認值,這些內存都將在方法區(qū)中進行分配。準備階段不分配類中的實例變量的內存,實例變量將會在對象實例化時隨著對象一起分配在 Java 堆中。
public static int value=123;*//在準備階段 value 初始值為 0 。在初始化階段才會變 *
為 123 。
解析
該階段主要完成符號引用到直接引用的轉換動作。解析動作并不一定在初始化動作完成之前,也有可能在初始化之后。
初始化
初始化時類加載的最后一步,前面的類加載過程,除了在加載階段用戶應用程序可以通過
自定義類加載器參與之外,其余動作完全由虛擬機主導和控制。到了初始化階段,才真正開始執(zhí)行類中定義的 Java 程序代碼。
17. 簡述 java 類加載機制?
虛擬機把描述類的數據從 Class 文件加載到內存,并對數據進行校驗,解析和初始化,最終形成可以被虛擬機直接使用的 java 類型。
18. 類加載器雙親委派模型機制?
當一個類收到了類加載請求時,不會自己先去加載這個類,而是將其委派給父類,由父類去加載,如果此時父類不能加載,反饋給子類,由子類去完成類的加載。
19.什么是類加載器,類加載器有哪些?
實現通過類的權限定名獲取該類的二進制字節(jié)流的代碼塊叫做類加載器。
主要有一下四種類加載器:
- 啟動類加載器(Bootstrap ClassLoader)用來加載 java 核心類庫,無法被 java 程序直接引用。
- 擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載 Java 類。
- 系統類加載器(system class loader):它根據 Java 應用的類路徑(CLASSPATH) 來加載 Java 類。一般來說,Java 應用的類都是由它來完成加載的??梢酝ㄟ^
ClassLoader.getSystemClassLoader()來獲取它。
用戶自定義類加載器,通過繼承 java.lang.ClassLoader 類的方式實現。
20.簡述 java 內存分配與回收策率以及 Minor GC 和Major GC
對象優(yōu)先在堆的 Eden 區(qū)分配。大對象直接進入老年代.3. 長期存活的對象將直接進入老年代. 當 Eden 區(qū)沒有足夠的空間進行分配時,虛擬機會執(zhí)行一次 Minor GC.Minor Gc 通常發(fā)生在新生代的 Eden 區(qū),在這個區(qū)的對象生存期短,往往發(fā)生 Gc 的頻率較高, 回收速度比較快;Full Gc/Major GC 發(fā)生在老年代,一般情況下,觸發(fā)老年代 GC 的時候不會觸發(fā) Minor GC,但是通過配置,可以在 Full GC 之前進行一次 Minor GC 這樣可以加快老年代的回收速度。
到此這篇關于2020年JVM高頻率面試題整理的文章就介紹到這了,更多相關2020年JVM面試題內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持腳本之家!
相關文章
這篇文章主要介紹了10道JVM常見面試題解析(附答案),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學2020-09-04
這篇文章主要介紹了JVM相關面試題及答案(小結),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-09-022020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案(史上最全)
這篇文章主要介紹了2020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-06-15
這篇文章主要介紹了JVM面試題小結(2020最新版),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-02-21- 這篇文章主要介紹了2019年JVM面試都問了什么?(附答案解析),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-12-04
Java研發(fā)面試99題(含答案):JVM+Spring+MySQL+線程池+鎖
這篇文章主要介紹了Java研發(fā)面試99題,主要包括了JVM,Spring,MySQL,線程池,鎖等,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-07-16
JVM(Java 虛擬機)算是面試必問的問題的了,而但凡問 JVM 一定會問的第一個問題就是:講一講 JVM 的組成?那本文就注重講一下 JVM 的組成,感興趣的可以了解一下2019-04-10
這篇文章主要介紹了30道有趣的JVM面試題(小結),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-11-26



