目錄
什么是程序計(jì)數(shù)器?
你能給我詳細(xì)的介紹Java堆嗎?
什么是虛擬機(jī)棧
1. 垃圾回收是否涉及棧內(nèi)存?
2. 棧內(nèi)存分配越大越好嗎?
3. 方法內(nèi)的局部變量是否線程安全?
4.什么情況下會(huì)導(dǎo)致棧內(nèi)存溢出?
5.堆棧的區(qū)別是什么?
能不能解釋一下方法區(qū)(元空間)?
常量池
運(yùn)行時(shí)常量池
你聽過直接內(nèi)存嗎?
什么是類加載器,類加載器有哪些
什么是雙親委派模型?
說一下類裝載的執(zhí)行過程?
對象什么時(shí)候可以被垃圾器回收
引用計(jì)數(shù)法
可達(dá)性分析算法
哪些對象可以作為 GC Root ?
JVM 垃圾回收算法有哪些?
說一下JVM中的分代回收
MinorGC、 Mixed GC 、 FullGC的區(qū)別是什么
說一下JVM有哪些垃圾回收器?
串行垃圾收集器
并行垃圾收集器
CMS(并發(fā))垃圾收集器
G1垃圾收集器
詳細(xì)聊一下G1垃圾回收器
強(qiáng)引用、軟引用、弱引用、虛引用的區(qū)別
JVM 調(diào)優(yōu)的參數(shù)可以在哪里設(shè)置參數(shù)值
JVM 調(diào)優(yōu)的參數(shù)都有哪些?
設(shè)置堆空間大小
堆空間設(shè)置多少合適?
虛擬機(jī)棧的設(shè)置
年輕代中Eden區(qū)和兩個(gè)Survivor區(qū)的大小比例
年輕代晉升老年代閾值
設(shè)置垃圾回收收集器
說一下 JVM 調(diào)優(yōu)的工具?
jps
jstack
jmap
jstat
總結(jié)垃圾回收統(tǒng)計(jì)
垃圾回收統(tǒng)計(jì)
jconsole
VisualVM
Java內(nèi)存泄露的排查思路?
CPU飆高排查方案與思路?
什么是程序計(jì)數(shù)器?
線程私有的,內(nèi)部保存的字節(jié)碼的行號。用于記錄正在執(zhí)行的字節(jié)碼指令的地址。
javap -v ?xx.class ? ?打印堆棧大小,局部變量的數(shù)量和方法的參數(shù)。
你能給我詳細(xì)的介紹Java堆嗎?
線程共享的區(qū)域:主要用來保存對象實(shí)例,數(shù)組等,當(dāng)堆中沒有內(nèi)存空間可分配給實(shí)例,也無法再擴(kuò)展時(shí),則拋出OutOfMemoryError異常。
元空間保存的類信息、靜態(tài)變量、常量、編譯后的代碼
年輕代被劃分為三部分,Eden區(qū)和兩個(gè)大小嚴(yán)格相同的Survivor區(qū),根據(jù)JVM的策略,在經(jīng)過幾次垃圾收集后,任然存活于Survivor的對象將被移動(dòng)到老年代區(qū)間。
老年代主要保存生命周期長的對象,一般是一些老的對象
什么是虛擬機(jī)棧
每個(gè)線程運(yùn)行時(shí)所需要的內(nèi)存,稱為虛擬機(jī)棧,先進(jìn)后出
每個(gè)棧由多個(gè)棧幀(frame)組成,對應(yīng)著每次方法調(diào)用時(shí)所占用的內(nèi)存
每個(gè)線程只能有一個(gè)活動(dòng)棧幀,對應(yīng)著當(dāng)前正在執(zhí)行的那個(gè)方法
1. 垃圾回收是否涉及棧內(nèi)存?
垃圾回收主要指就是堆內(nèi)存,當(dāng)棧幀彈棧以后,內(nèi)存就會(huì)釋放
2. 棧內(nèi)存分配越大越好嗎?
未必,默認(rèn)的棧內(nèi)存通常為1024k
棧幀過大會(huì)導(dǎo)致線程數(shù)變少,例如,機(jī)器總內(nèi)存為512m,目前能活動(dòng)的線程數(shù)則為512個(gè),如果把棧內(nèi)存改為2048k,那么能活動(dòng)的棧幀就會(huì)減半
3. 方法內(nèi)的局部變量是否線程安全?
如果方法內(nèi)局部變量沒有逃離方法的作用范圍,它是線程安全的
如果是局部變量引用了對象,并逃離方法的作用范圍,需要考慮線程安全
4.什么情況下會(huì)導(dǎo)致棧內(nèi)存溢出?
棧幀過多導(dǎo)致棧內(nèi)存溢出,典型問題:遞歸調(diào)用
棧幀過大導(dǎo)致棧內(nèi)存溢出
5.堆棧的區(qū)別是什么?
棧內(nèi)存一般會(huì)用來存儲(chǔ)局部變量和方法調(diào)用,但堆內(nèi)存是用來存儲(chǔ)Java對象和數(shù)組的的。
堆會(huì)GC垃圾回收,而棧不會(huì)。
棧內(nèi)存是線程私有的,而堆內(nèi)存是線程共有的。
兩者異常錯(cuò)誤不同,但如果棧內(nèi)存或者堆內(nèi)存不足都會(huì)拋出異常。 ? ? ?
??臻g不足:java.lang.StackOverFlowError。 ? ? ?
堆空間不足:java.lang.OutOfMemoryError。
能不能解釋一下方法區(qū)(元空間)?
方法區(qū)(Method Area)是各個(gè)線程共享的內(nèi)存區(qū)域
主要存儲(chǔ)類的信息、運(yùn)行時(shí)常量池
虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建,關(guān)閉虛擬機(jī)時(shí)釋放
如果方法區(qū)域中的內(nèi)存無法滿足分配請求,則會(huì)拋出OutOfMemoryError: Metaspace
常量池
可以看作是一張表,虛擬機(jī)指令根據(jù)這張常量表找到要執(zhí)行的類名、方法名、參數(shù)類型、字面量等信息
javap -v Application.class????????查看字節(jié)碼結(jié)構(gòu)(類的基本信息、常量池、方法定義)
運(yùn)行時(shí)常量池
常量池是 *.class 文件中的,當(dāng)該類被加載,它的常量池信息就會(huì)放入運(yùn)行時(shí)常量池,并把里面的符號地址變?yōu)檎鎸?shí)地址
你聽過直接內(nèi)存嗎?
直接內(nèi)存:并不屬于JVM中的內(nèi)存結(jié)構(gòu),不由JVM進(jìn)行管理。是虛擬機(jī)的系統(tǒng)內(nèi)存,常見于 NIO 操作時(shí),用于數(shù)據(jù)緩沖區(qū),它分配回收成本較高,但讀寫性能高,不受 JVM 內(nèi)存回收管理
常規(guī)IO的數(shù)據(jù)拷貝流程
什么是類加載器,類加載器有哪些
類加載器
JVM只會(huì)運(yùn)行二進(jìn)制文件,類加載器的作用就是將字節(jié)碼文件加載到JVM中,從而讓Java程序能夠啟動(dòng)起來。
什么是雙親委派模型?
加載某一個(gè)類,先委托上一級的加載器進(jìn)行加載,如果上級加載器也有上級,則會(huì)繼續(xù)向上委托,如果該類委托上級沒有被加載,子加載器嘗試加載該類
(1)通過雙親委派機(jī)制可以避免某一個(gè)類被重復(fù)加載,當(dāng)父類已經(jīng)加載后則無需重復(fù)加載,保證唯一性。
(2)為了安全,保證類庫API不會(huì)被修改
說一下類裝載的執(zhí)行過程?
加載:查找和導(dǎo)入class文件
驗(yàn)證:保證加載類的準(zhǔn)確性
準(zhǔn)備:為類變量分配內(nèi)存并設(shè)置類變量初始值
解析:把類中的符號引用轉(zhuǎn)換為直接引用
初始化:對類的靜態(tài)變量,靜態(tài)代碼塊執(zhí)行初始化操作
使用:JVM 開始從入口方法開始執(zhí)行用戶的程序代碼
卸載:當(dāng)用戶程序代碼執(zhí)行完畢后,JVM便開始銷毀創(chuàng)建的Class對象。
對象什么時(shí)候可以被垃圾器回收
如果一個(gè)或多個(gè)對象沒有任何的引用指向它了,那么這個(gè)對象現(xiàn)在就是垃圾,如果定位了垃圾,則有可能會(huì)被垃圾回收器回收。
引用計(jì)數(shù)法
一個(gè)對象被引用了一次,在當(dāng)前的對象頭上遞增一次引用次數(shù),如果這個(gè)對象的引用次數(shù)為0,代表這個(gè)對象可回收
當(dāng)對象間出現(xiàn)了循環(huán)引用的話,則引用計(jì)數(shù)法就會(huì)失效
循環(huán)引用,會(huì)引發(fā)內(nèi)存泄露
可達(dá)性分析算法
現(xiàn)在的虛擬機(jī)采用的都是通過可達(dá)性分析算法來確定哪些內(nèi)容是垃圾。
X,Y這兩個(gè)節(jié)點(diǎn)是可回收的
Java ?虛擬機(jī)中的垃圾回收器采用可達(dá)性分析來探索所有存活的對象
掃描堆中的對象,看是否能夠沿著 GC Root 對象 為起點(diǎn)的引用鏈找到該對象,找不到,表示可以回收
哪些對象可以作為 GC Root ?
虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象
方法區(qū)中類靜態(tài)屬性引用的對象
方法區(qū)中常量引用的對象
本地方法棧中 JNI(即一般說的 Native 方法)引用的對象
JVM 垃圾回收算法有哪些?
標(biāo)記清除算法:垃圾回收分為2個(gè)階段,分別是標(biāo)記和清除,效率高,有磁盤碎片,內(nèi)存不連續(xù)
標(biāo)記整理算法:標(biāo)記清除算法一樣,將存活對象都向內(nèi)存另一端移動(dòng),然后清理邊界以外的垃圾,無碎片,對象需要移動(dòng),效率低
復(fù)制算法:將原有的內(nèi)存空間一分為二,每次只用其中的一塊,正在使用的對象復(fù)制到另一個(gè)內(nèi)存空間中,然后將該內(nèi)存空間清空,交換兩個(gè)內(nèi)存的角色,完成垃圾的回收;無碎片,內(nèi)存使用率低
說一下JVM中的分代回收
在java8時(shí),堆被分為了兩份:新生代和老年代【1:2】
對于新生代,內(nèi)部又被分為了三個(gè)區(qū)域。
伊甸園區(qū)Eden,新生的對象都分配到這里
幸存者區(qū)survivor(分成from和to)
Eden區(qū),from區(qū),to區(qū)【8:1:1】
新創(chuàng)建的對象,都會(huì)先分配到eden區(qū)
當(dāng)伊甸園內(nèi)存不足,標(biāo)記伊甸園與 from(現(xiàn)階段沒有)的存活對象
將存活對象采用復(fù)制算法復(fù)制到to中,復(fù)制完畢后,伊甸園和 from 內(nèi)存都得到釋放
經(jīng)過一段時(shí)間后伊甸園的內(nèi)存又出現(xiàn)不足,標(biāo)記eden區(qū)域to區(qū)存活的對象,將其復(fù)制到from區(qū)
當(dāng)幸存區(qū)對象熬過幾次回收(最多15次),晉升到老年代(幸存區(qū)內(nèi)存不足或大對象會(huì)提前晉升)
MinorGC、 Mixed GC 、 FullGC的區(qū)別是什么
MinorGC【young GC】發(fā)生在新生代的垃圾回收,暫停時(shí)間短(STW)
Mixed GC 新生代 + 老年代部分區(qū)域的垃圾回收,G1 收集器特有
FullGC: 新生代 + 老年代完整垃圾回收,暫停時(shí)間長(STW),應(yīng)盡力避免
STW(Stop-The-World):暫停所有應(yīng)用程序線程,等待垃圾回收的完成
說一下JVM有哪些垃圾回收器?
串行垃圾收集器
Serial 作用于新生代,采用復(fù)制算法
Serial Old 作用于老年代,采用標(biāo)記-整理算法
垃圾回收時(shí),只有一個(gè)線程在工作,并且java應(yīng)用中的所有線程都要暫停(STW),等待垃圾回收的完成。
并行垃圾收集器
Parallel New作用于新生代,采用復(fù)制算法
Parallel Old作用于老年代,采用標(biāo)記-整理算法
垃圾回收時(shí),多個(gè)線程在工作,并且java應(yīng)用中的所有線程都要暫停(STW),等待垃圾回收的完成。
CMS(并發(fā))垃圾收集器
是一款并發(fā)的、使用標(biāo)記-清除算法的垃圾回收器,該回收器是針對老年代垃圾回收的,是一款以獲取最短回收停頓時(shí)間為目標(biāo)的收集器,停頓時(shí)間短,用戶體驗(yàn)就好。其最大特點(diǎn)是在進(jìn)行垃圾回收時(shí),應(yīng)用仍然能正常運(yùn)行。
G1垃圾收集器
作用在新生代和老年代
詳細(xì)聊一下G1垃圾回收器
應(yīng)用于新生代和老年代,在JDK9之后默認(rèn)使用G1
劃分成多個(gè)區(qū)域,每個(gè)區(qū)域都可以充當(dāng) eden,survivor,old, humongous,其中 humongous 專為大對象準(zhǔn)備
用復(fù)制算法
響應(yīng)時(shí)間與吞吐量兼顧 分成三個(gè)階段:新生代回收、并發(fā)標(biāo)記、混合收集
如果并發(fā)失敗(即回收速度趕不上創(chuàng)建新對象速度),會(huì)觸發(fā) Full GC
強(qiáng)引用、軟引用、弱引用、虛引用的區(qū)別
強(qiáng)引用:只要所有 GC Roots 能找到,就不會(huì)被回收
軟引用:需要配合SoftReference使用,當(dāng)垃圾多次回收,內(nèi)存依然不夠的時(shí)候會(huì)回收軟引用對象
弱引用:需要配合WeakReference使用,只要進(jìn)行了垃圾回收,就會(huì)把弱引用對象回收
虛引用:必須配合引用隊(duì)列使用,被引用對象回收時(shí),會(huì)將虛引用入隊(duì),由 Reference Handler 線程調(diào)用虛引用相關(guān)方法釋放直接內(nèi)存
JVM 調(diào)優(yōu)的參數(shù)可以在哪里設(shè)置參數(shù)值
war包部署在tomcat中設(shè)置
修改TOMCAT_HOME/bin/catalina.sh文件
jar包部署在啟動(dòng)參數(shù)設(shè)置
java -Xms512m -Xmx1024m -jar xxxx.jar
JVM 調(diào)優(yōu)的參數(shù)都有哪些?
設(shè)置堆空間大小
-Xms:設(shè)置堆的初始化大小
-Xmx:設(shè)置堆的最大大小
-Xms:1024
-Xms:1024k
-Xms:1024m
-Xms:1g
不指定單位默認(rèn)為字節(jié)
指定單位,按照指定的單位設(shè)置
堆空間設(shè)置多少合適?
最大大小的默認(rèn)值是物理內(nèi)存的1/4,初始大小是物理內(nèi)存的1/64
堆太小,可能會(huì)頻繁的導(dǎo)致年輕代和老年代的垃圾回收,會(huì)產(chǎn)生stw,暫停用戶線程
堆內(nèi)存大肯定是好的,存在風(fēng)險(xiǎn),假如發(fā)生了fullgc,它會(huì)掃描整個(gè)堆空間,暫停用戶線程的時(shí)間長
設(shè)置參考推薦:盡量大,也要考察一下當(dāng)前計(jì)算機(jī)其他程序的內(nèi)存使用情況
虛擬機(jī)棧的設(shè)置
虛擬機(jī)棧的設(shè)置:每個(gè)線程默認(rèn)會(huì)開啟1M的內(nèi)存,用于存放棧幀、調(diào)用參數(shù)、局部變量等,但一般256K就夠用。通常減少每個(gè)線程的堆棧,可以產(chǎn)生更多的線程,但這實(shí)際上還受限于操作系統(tǒng)。
-Xss ? 對每個(gè)線程stack大小的調(diào)整,-Xss128k
年輕代中Eden區(qū)和兩個(gè)Survivor區(qū)的大小比例
設(shè)置年輕代中Eden區(qū)和兩個(gè)Survivor區(qū)的大小比例。該值如果不設(shè)置,則默認(rèn)比例為8:1:1。通過增大Eden區(qū)的大小,來減少YGC發(fā)生的次數(shù),但有時(shí)我們發(fā)現(xiàn),雖然次數(shù)減少了,但Eden區(qū)滿的時(shí)候,由于占用的空間較大,導(dǎo)致釋放緩慢,此時(shí)STW的時(shí)間較長,因此需要按照程序情況去調(diào)優(yōu)。
-XXSurvivorRatio=8? ? //表示年輕代中的分配比率:survivor:eden = 2:8
年輕代晉升老年代閾值
-XX:MaxTenuringThreshold=threshold
默認(rèn)為15
取值范圍0-15
設(shè)置垃圾回收收集器
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:+UseG1GC
說一下 JVM 調(diào)優(yōu)的工具?
jps
進(jìn)程狀態(tài)信息
jstack
jstack [option] <pid>
查看java進(jìn)程內(nèi)線程的堆棧信息
jmap
用于生成堆轉(zhuǎn)內(nèi)存快照、內(nèi)存使用情況
jmap -heap pid ? 顯示Java堆的信息
jmap -dump:format=b,file=heap.hprof pid
format=b表示以hprof二進(jìn)制格式轉(zhuǎn)儲(chǔ)Java堆的內(nèi)存
file=<filename>用于指定快照dump文件的文件名。
它是一個(gè)進(jìn)程或系統(tǒng)在某一給定的時(shí)間的快照。比如在進(jìn)程崩潰時(shí),甚至是任何時(shí)候,我們都可以通過工具將系統(tǒng)或某進(jìn)程的內(nèi)存?zhèn)浞莩鰜砉┱{(diào)試分析用。dump文件中包含了程序運(yùn)行的模塊信息、線程信息、堆棧調(diào)用信息、異常信息等數(shù)據(jù),方便系統(tǒng)技術(shù)人員進(jìn)行錯(cuò)誤排查。
jstat
是JVM統(tǒng)計(jì)監(jiān)測工具??梢杂脕盹@示垃圾回收信息、類加載信息、新生代統(tǒng)計(jì)信息等。
總結(jié)垃圾回收統(tǒng)計(jì)
jstat -gcutil pid
垃圾回收統(tǒng)計(jì)
jstat -gc pid
jconsole
用于對jvm的內(nèi)存,線程,類 的監(jiān)控,是一個(gè)基于 jmx 的 GUI 性能監(jiān)控工具
打開方式:java 安裝目錄 bin目錄下 直接啟動(dòng) jconsole.exe 就行
VisualVM
能夠監(jiān)控線程,內(nèi)存情況,查看方法的CPU時(shí)間和內(nèi)存中的對 象,已被GC的對象,反向查看分配的堆棧
打開方式:java 安裝目錄 bin目錄下 直接啟動(dòng) jvisualvm.exe就行
Java內(nèi)存泄露的排查思路?
內(nèi)存泄漏通常是指堆內(nèi)存,通常是指一些大對象不被回收的情況
1、通過jmap或設(shè)置jvm參數(shù)獲取堆內(nèi)存快照dump
2、通過工具, VisualVM去分析dump文件,VisualVM可以加載離線的dump文件
3、通過查看堆信息的情況,可以大概定位內(nèi)存溢出是哪行代碼出了問題
4、找到對應(yīng)的代碼,通過閱讀上下文的情況,進(jìn)行修復(fù)即可
CPU飆高排查方案與思路?
1.使用top命令查看占用cpu的情況
2.通過top命令查看后,可以查看是哪一個(gè)進(jìn)程占用cpu較高
3.使用ps命令查看進(jìn)程中的線程信息文章來源:http://www.zghlxwxcb.cn/news/detail-699855.html
4.使用jstack命令查看進(jìn)程中哪些線程出現(xiàn)了問題,最終定位問題文章來源地址http://www.zghlxwxcb.cn/news/detail-699855.html
到了這里,關(guān)于Java后端開發(fā)面試題——JVM虛擬機(jī)篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!