2020的“金9銀10”已經(jīng)到了渊啰,現(xiàn)在是各位找工作的最佳時間,今天筆者在這里給各位整理了2020大廠關于JVM經(jīng)常出現(xiàn)的高頻率面試題給整理了出來單獨寫了一篇文章申屹,各位的一些知識盲點希望能在這里得到解決绘证!
1.內(nèi)存模型以及分區(qū),需要詳細到每個區(qū)放什么哗讥。
JVM 分為堆區(qū)和棧區(qū)嚷那,還有方法區(qū),初始化的對象放在堆里面杆煞,引用放在棧里面魏宽, class 類信息常量池(static 常量和 static 變量)等放在方法區(qū) new: ? 方法區(qū):主要是存儲類信息,常量池(static 常量和 static 變量)决乎,編譯后的代碼(字節(jié)碼)等數(shù)據(jù)? 堆:初始化的對象队询,成員變量 (那種非 static 的變量),所有的對象實例和數(shù)組都要在堆上分配
棧:棧的結構是棧幀組成的构诚,調(diào)用一個方法就壓入一幀娘摔,幀上面存儲局部變量表,操作數(shù)棧唤反,方法出口等信息凳寺,局部變量表存放的是 8 大基礎類型加上一個應用類型鸭津,所以還是一個指向地址的指針? 本地方法棧:主要為 Native 方法服務? 程序計數(shù)器:記錄當前線程執(zhí)行的行號
2. 堆里面的分區(qū):Eden,survival (from+ to)肠缨,老年代逆趋,各自的特點。
堆里面分為新生代和老生代(java8 取消了永久代晒奕,采用了 Metaspace)闻书,新生代包 含 Eden+Survivor 區(qū),survivor 區(qū)里面分為 from 和 to 區(qū)脑慧,內(nèi)存回收時魄眉,如果用的是復制算法,從 from 復制到 to闷袒,當經(jīng)過一次或者多次 GC 之后坑律,存活下來的對象會被移動到老年區(qū),當 JVM 內(nèi)存不夠用的時候囊骤,會觸發(fā) Full GC晃择,清理 JVM 老年區(qū)當新生區(qū)滿了之后會觸發(fā) YGC,先把存活的對象放到其中一個 Survice 區(qū),然后進行垃圾清理也物。因為如果僅僅清理需要刪除的對象宫屠,這樣會導致內(nèi)存碎片,因此一般會把 Eden 進行完全的清理滑蚯,然后整理內(nèi)存浪蹂。那么下次 GC 的時候, 就會使用下一個 Survive告材,這樣循環(huán)使用坤次。如果有特別大的對象,新生代放不下创葡,就會使用老年代的擔保浙踢,直接放到老年代里面绢慢。因為 JVM 認為灿渴,一般大對象的存 活時間一般比較久遠。
3. 對象創(chuàng)建方法胰舆,對象的內(nèi)存分配骚露,對象的訪問定位。
new 一個對象
4. GC 的兩種判定方法:
引用計數(shù)法:指的是如果某個地方引用了這個對象就+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)
方法返回前
調(diào)用方法的 call 之后
拋出異常的位置
6. GC 的三種收集方法:標記清除、標記整理蹋嵌、復制算法的原理與特點育瓜,分別用
在什么地方,如果讓你優(yōu)化收集方法栽烂,有什么思路躏仇?先標記,標記完畢之后再清除腺办,效率不高焰手,會產(chǎn)生碎片復制算法:分為 8:1 的 Eden 區(qū)和 survivor 區(qū),就是上面談到的 YGC標記整理:標記完畢之后怀喉,讓所有存活的對象向一端移動
7. GC 收集器有哪些书妻?CMS 收集器與 G1 收集器的特點。
并行收集器:串行收集器使用一個單獨的線程進行收集磺送,GC 時服務有停頓時間串行收集器:次要回收中使用多線程來執(zhí)行
CMS 收集器是基于“標記清除”算法實現(xiàn)的驻子,經(jīng)過多次標記才會被清除
G1 從**整體來看是基于****“標記—整理”算法實現(xiàn)的收集器,從局部(兩個 Region 之間上來看是基于“復制”算法實現(xiàn)的
8. Minor GC 與 Full GC 分別在什么時候發(fā)生估灿?
新生代內(nèi)存不夠用時候發(fā)生 MGC 也叫 YGC崇呵,JVM 內(nèi)存不夠的時候發(fā)生 FGC
9. 幾種常用的內(nèi)存調(diào)試工具:jmap、jstack馅袁、jconsole域慷、jhat
jstack 可以看當前棧的情況,jmap 查看內(nèi)存汗销,jhat 進行 dump 堆的信息
mat(eclipse 的也要了解一下)
10. 類加載的幾個過程:
加載犹褒、驗證、準備弛针、解析叠骑、初始化。然后是使用和卸載了
通過全限定名來加載生成 class 對象到內(nèi)存中削茁,然后進行驗證這個 class 文件宙枷,包括文件格式校驗、元數(shù)據(jù)驗證茧跋,字節(jié)碼校驗等慰丛。準備是對這個對象分配內(nèi)存。解析是將符
號引用轉化為直接引用(指針引用)瘾杭,初始化就是開始執(zhí)行構造器的代碼
11.JVM 內(nèi)存分哪幾個區(qū)诅病,每個區(qū)的作用是什么?
java 虛擬機主要分為以下一個區(qū):
方法區(qū):
有時候也成為永久代,在該區(qū)內(nèi)很少發(fā)生垃圾回收,但是并不代表不發(fā)生 GC贤笆,在這里進行的 GC 主要是對方法區(qū)里的常量池和對類型的卸載
方法區(qū)主要用來存儲已被虛擬機加載的類的信息蝇棉、常量、靜態(tài)變量和即時編譯器編譯后的代碼等數(shù)據(jù)芥永。
該區(qū)域是被線程共享的银萍。
方法區(qū)里有一個運行時常量池,用于存放靜態(tài)編譯產(chǎn)生的字面量和符號引用恤左。該常量池具有動態(tài)性贴唇,也就是說常量并不一定是編譯時確定,運行時生成的常量也會存在這個常量池中飞袋。
虛擬機棧:
虛擬機棧也就是我們平常所稱的棧內(nèi)存,它為 java 方法服務戳气,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀,用于存儲局部變量表巧鸭、操作數(shù)棧瓶您、動態(tài)鏈接和方法出口等信息。
虛擬機棧是線程私有的纲仍,它的生命周期與線程相同呀袱。
局部變量表里存儲的是基本數(shù)據(jù)類型、returnAddress 類型(指向一條字節(jié)碼指令的地址)和對象引用郑叠,這個對象引用有可能是指向?qū)ο笃鹗嫉刂返囊粋€指針夜赵,也有可能是代表對象的句柄或者與對象相關聯(lián)的位置。局部變量所需的內(nèi)存空間在編譯器間確定
4.操作數(shù)棧的作用主要用來存儲運算結果以及運算的操作數(shù)乡革,它不同于局部變量表通過索
引來訪問寇僧,而是壓棧和出棧的方式
5.每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了
支持方法調(diào)用過程中的動態(tài)連接.動態(tài)鏈接就是將常量池中的符號引用在運行期轉化為直接
引用沸版。
本地方法棧
本地方法棧和虛擬機棧類似嘁傀,只不過本地方法棧為 Native 方法服務。
堆
java 堆是所有線程所共享的一塊內(nèi)存视粮,在虛擬機啟動時創(chuàng)建细办,幾乎所有的對象實例都在這里創(chuàng)建,因此該區(qū)域經(jīng)常發(fā)生垃圾回收操作蕾殴。
程序計數(shù)器
內(nèi)存空間小笑撞,字節(jié)碼解釋器工作時通過改變這個計數(shù)值可以選取下一條需要執(zhí)行的字節(jié)碼
指令,分支区宇、循環(huán)娃殖、跳轉值戳、異常處理和線程恢復等功能都需要依賴這個計數(shù)器完成议谷。該內(nèi)
存區(qū)域是唯一一個 java 虛擬機規(guī)范沒有規(guī)定任何 OOM 情況的區(qū)域。
12.如和判斷一個對象是否存活?(或者 GC 對象的判定方法
判斷一個對象是否存活有兩種方法:
引用計數(shù)法
所謂引用計數(shù)法就是給每一個對象設置一個引用計數(shù)器堕虹,每當有一個地方引用這個對象時卧晓,就將計數(shù)器加一芬首,引用失效時,計數(shù)器就減一逼裆。當一個對象的引用計數(shù)器為零時郁稍,說明此對象沒有被引用,也就是“死對象”,將會被垃圾回收.
引用計數(shù)法有一個缺陷就是無法解決循環(huán)引用問題胜宇,也就是說當對象 A 引用對象 B耀怜,對象
B 又引用者對象 A,那么此時 A,B 對象的引用計數(shù)器都不為零桐愉,也就造成無法完成垃圾回收财破,所以主流的虛擬機都沒有采用這種算法。
2.可達性算法(引用鏈法)
該算法的思想是:從一個被稱為 GC Roots的對象開始向下搜索从诲,如果一個對象到 GC
Roots 沒有任何引用鏈相連時左痢,則說明此對象不可用。
在 java 中可以作為 GC Roots 的對象有以下幾種:
虛擬機棧中引用的對象
方法區(qū)類靜態(tài)屬性引用的對象
方法區(qū)常量池引用的對象
本地方法棧 JNI 引用的對象
雖然這些算法可以判定一個對象是否能被回收系洛,但是當滿足上述條件時俊性,一個對象比不一定會被回收。當一個對象不可達 GC Root 時描扯,這個對象并不會立馬被回收定页,而是出于一個死緩的階段,若要被真正的回收需要經(jīng)歷兩次標記
如果對象在可達性分析中沒有與 GC Root 的引用鏈绽诚,那么此時就會被第一次標記并且進行一次篩選拯勉,篩選的條件是是否有必要執(zhí)行 finalize()方法。當對象沒有覆蓋 finalize()方法或者已被虛擬機調(diào)用過憔购,那么就認為是沒必要的宫峦。
如果該對象有必要執(zhí)行 finalize()方法,那么這個對象將會放在一個稱為 F-Queue 的對隊列中玫鸟,虛擬機會觸發(fā)一個 Finalize()線程去執(zhí)行导绷,此線程是低優(yōu)先級的,并且虛擬機不會承
諾一直等待它運行完屎飘,這是因為如果 finalize()執(zhí)行緩慢或者發(fā)生了死鎖妥曲,那么就會造成 F?Queue 隊列一直等待,造成了內(nèi)存回收系統(tǒng)的崩潰钦购。GC 對處于 F-Queue 中的對象進行第二次被標記檐盟,這時,該對象將被移除”即將回收”集合押桃,等待回收葵萎。
13.簡述 java 垃圾回收機制?
在 java 中,程序員是不需要顯示的去釋放一個對象的內(nèi)存的,而是由虛擬機自行執(zhí)行羡忘。在JVM 中谎痢,有一個垃圾回收線程,它是低優(yōu)先級的卷雕,在正常情況下是不會執(zhí)行的节猿,只有在虛擬機空閑或者當前堆內(nèi)存不足時,才會觸發(fā)執(zhí)行漫雕,掃面那些沒有被任何引用的對象滨嘱,并將它們添加到要回收的集合中,進行回收浸间。
14.java 中垃圾收集的方法有哪些?
標記-清除: 這是垃圾收集算法中最基礎的九孩,根據(jù)名字就可以知道,它的思想就是標記哪些要被回收的對象发框,然后統(tǒng)一回收躺彬。這種方法很簡單,但是會有兩個主要問題:1.效率不高梅惯,標記和清除的效率都很低宪拥;2.會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,導致以后程序在分配較大的對象時铣减,由于沒有充足的連續(xù)內(nèi)存而提前觸發(fā)一次 GC 動作她君。
復制算法: 為了解決效率問題,復制算法將可用內(nèi)存按容量劃分為相等的兩部分葫哗,然后每次只使用其中的一塊缔刹,當一塊內(nèi)存用完時,就將還存活的對象復制到第二塊內(nèi)存上劣针,然
后一次性清楚完第一塊內(nèi)存校镐,再將第二塊上的對象復制到第一塊。但是這種方式捺典,內(nèi)存的代價太高鸟廓,每次基本上都要浪費一般的內(nèi)存。
于是將該算法進行了改進襟己,內(nèi)存區(qū)域不再是按照 1:1 去劃分引谜,而是將內(nèi)存劃分為8:1:1 三部分,較大那份內(nèi)存交 Eden 區(qū)擎浴,其余是兩塊較小的內(nèi)存區(qū)叫 Survior 區(qū)员咽。
每次都會優(yōu)先使用 Eden 區(qū),若 Eden 區(qū)滿贮预,就將對象復制到第二塊內(nèi)存區(qū)上贝室,然
后清除 Eden 區(qū)契讲,如果此時存活的對象太多,以至于 Survivor 不夠時档玻,會將這些對象通過分配擔保機制復制到老年代中。(java 堆又分為新生代和老年代)
標記-整理該算法主要是為了解決標記-清除茫藏,產(chǎn)生大量內(nèi)存碎片的問題误趴;當對象存活率較高時,也解決了復制算法的效率問題务傲。它的不同之處就是在清除對象的時候現(xiàn)將可回
收對象移動到一端凉当,然后清除掉端邊界以外的對象,這樣就不會產(chǎn)生內(nèi)存碎片了售葡。
分代收集現(xiàn)在的虛擬機垃圾收集大多采用這種方式看杭,它根據(jù)對象的生存周期,將堆分為新生代和老年代挟伙。在新生代中楼雹,由于對象生存期短,每次回收都會有大量對象死去尖阔,那么這時就采用復制算法贮缅。老年代里的對象存活率較高,沒有額外的空間進行分配擔保介却,所以可以使用標記-整理或者 標記-清除谴供。
15.java 內(nèi)存模型
java 內(nèi)存模型(JMM)是線程間通信的控制機制.JMM 定義了主內(nèi)存和線程之間抽象關系。
線程之間的共享變量存儲在主內(nèi)存(main memory)中齿坷,每個線程都有一個私有的本地內(nèi)存(local memory)桂肌,本地內(nèi)存中存儲了該線程以讀/寫共享變量的副本。本地內(nèi)存是
JMM 的一個抽象概念永淌,并不真實存在崎场。它涵蓋了緩存,寫緩沖區(qū)遂蛀,寄存器以及其他的硬件和編譯器優(yōu)化照雁。Java 內(nèi)存模型的抽象示意圖如下:從上圖來看,線程 A 與線程 B 之間如要通信的話答恶,必須要經(jīng)歷下面 2 個步驟:
首先饺蚊,線程 A 把本地內(nèi)存 A 中更新過的共享變量刷新到主內(nèi)存中去。然后悬嗓,線程 B 到主內(nèi)存中去讀取線程 A 之前已更新過的共享變量污呼。
16.java 類加載過程?
java 類加載需要經(jīng)歷一下 7 個過程:
加載
加載時類加載的第一個過程,在這個階段包竹,將完成一下三件事情:
通過一個類的全限定名獲取該類的二進制流燕酷。
將該二進制流中的靜態(tài)存儲結構轉化為方法去運行時數(shù)據(jù)結構籍凝。
在內(nèi)存中生成該類的 Class 對象,作為該類的數(shù)據(jù)訪問入口苗缩。
驗證
驗證的目的是為了確保 Class 文件的字節(jié)流中的信息不回危害到虛擬機.在該階段主要完成
以下四鐘驗證:
文件格式驗證:驗證字節(jié)流是否符合 Class 文件的規(guī)范饵蒂,如主次版本號是否在當前虛擬機范圍內(nèi),常量池中的常量是否有不被支持的類型.
元數(shù)據(jù)驗證:對字節(jié)碼描述的信息進行語義分析酱讶,如這個類是否有父類退盯,是否集成了不被繼承的類等。
字節(jié)碼驗證:是整個驗證過程中最復雜的一個階段泻肯,通過驗證數(shù)據(jù)流和控制流的分析渊迁,確定程序語義是否正確,主要針對方法體的驗證灶挟。如:方法中的類型轉換是否正確琉朽,跳轉
指令是否正確等。4. 符號引用驗證:這個動作在后面的解析過程中發(fā)生稚铣,主要是為了確保解析動作能正確執(zhí)
行箱叁。
準備
準備階段是為類的靜態(tài)變量分配內(nèi)存并將其初始化為默認值,這些內(nèi)存都將在方法區(qū)中進行分配惕医。準備階段不分配類中的實例變量的內(nèi)存蝌蹂,實例變量將會在對象實例化時隨著對象一起分配在 Java 堆中。
public static int value=123;*//在準備階段 value 初始值為 0 曹锨。在初始化階段才會變 *
為 123 孤个。
解析
該階段主要完成符號引用到直接引用的轉換動作。解析動作并不一定在初始化動作完成之前沛简,也有可能在初始化之后齐鲤。
初始化
初始化時類加載的最后一步,前面的類加載過程椒楣,除了在加載階段用戶應用程序可以通過
自定義類加載器參與之外给郊,其余動作完全由虛擬機主導和控制。到了初始化階段捧灰,才真正開始執(zhí)行類中定義的 Java 程序代碼淆九。
17. 簡述 java 類加載機制?
虛擬機把描述類的數(shù)據(jù)從 Class 文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗毛俏,解析和初始化炭庙,最終形成可以被虛擬機直接使用的 java 類型。
18. 類加載器雙親委派模型機制煌寇?
當一個類收到了類加載請求時焕蹄,不會自己先去加載這個類,而是將其委派給父類阀溶,由父類去加載腻脏,如果此時父類不能加載鸦泳,反饋給子類,由子類去完成類的加載永品。
19.什么是類加載器做鹰,類加載器有哪些?
實現(xiàn)通過類的權限定名獲取該類的二進制字節(jié)流的代碼塊叫做類加載器。
主要有一下四種類加載器:
啟動類加載器(Bootstrap ClassLoader)用來加載 java 核心類庫鼎姐,無法被 java 程序直接引用钾麸。
擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現(xiàn)會提供一個擴展庫目錄症见。該類加載器在此目錄里面查找并加載 Java 類喂走。
系統(tǒng)類加載器(system class loader):它根據(jù) Java 應用的類路徑(CLASSPATH) 來加載 Java 類殃饿。一般來說谋作,Java 應用的類都是由它來完成加載的『醴迹可以通過
ClassLoader.getSystemClassLoader()來獲取它遵蚜。
用戶自定義類加載器,通過繼承 java.lang.ClassLoader 類的方式實現(xiàn)奈惑。
20.簡述 java 內(nèi)存分配與回收策率以及 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 這樣可以加快老年代的回收速度庶柿。
其實我們可以發(fā)現(xiàn)很多知識點是面試必問到的村怪。祝大家都能找到一分滿意的工作!加油!
近段時間正值找工作的最佳時間浮庐,本人將一些各大廠商的面試題和今年(2020)最新資料的收集甚负,以下是部分資料截圖(所有資料均已整合成文檔,pdf壓縮打包處理)审残。
如有有需要的朋友可以點擊這里來獲取資料梭域,暗號:qf