年底了达舒,xjjdog決定來一篇實(shí)用的硬核文章值朋。本篇文章多達(dá)38道
面試題,照顧到了JVM的方方面面巩搏,都是常見的題目昨登。如果背誦記憶下來,進(jìn)入大廠非常的easy贯底。
面試題不能坑人丰辣,所以本篇文章的內(nèi)容是經(jīng)過多次打磨的,現(xiàn)在放送給大家禽捆。
有些面試題是開放性的笙什,有些是知識(shí)性的,注意區(qū)別胚想。面試并沒有標(biāo)準(zhǔn)答案琐凭,尤其是開放性題目,你需要整理成白話文浊服,來盡量的展示自己统屈。
如果你在答案中描述了一些自己不是很熟悉的內(nèi)容,可能會(huì)受到追問牙躺。所以鸿吆,根據(jù)問題,整理一份適合自己的吧述呐,這比拿來主義更讓人印象深刻惩淳。
1、JVM有哪些內(nèi)存區(qū)域乓搬?(JVM的內(nèi)存布局是什么思犁?)
JVM包含堆
、元空間
进肯、Java虛擬機(jī)棧
激蹲、本地方法棧
、程序計(jì)數(shù)器
等內(nèi)存區(qū)域江掩。其中学辱,堆是占用內(nèi)存最大的一塊乘瓤。我們平常的-Xmx
、-Xms
等參數(shù)策泣,就是針對(duì)于堆進(jìn)行設(shè)計(jì)的衙傀。
- 堆:JVM堆中的數(shù)據(jù),是共享的萨咕,是占用內(nèi)存最大的一塊區(qū)域
- 虛擬機(jī)棧:Java虛擬機(jī)棧统抬,是基于線程的,用來服務(wù)字節(jié)碼指令的運(yùn)行
- 程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器
- 元空間:方法區(qū)就在這里危队,非堆本地內(nèi)存:其他的內(nèi)存占用空間
2聪建、Java的內(nèi)存模型是什么?(JMM是什么茫陆?)
JVM試圖定義一種統(tǒng)一的內(nèi)存模型金麸,能將各種底層硬件及操作系統(tǒng)的內(nèi)存訪問差異進(jìn)行封裝,使Java程序在不同硬件及操作系統(tǒng)上都能達(dá)到相同的并發(fā)效果簿盅。它分為工作內(nèi)存和主內(nèi)存钱骂,線程無法對(duì)主存儲(chǔ)器直接進(jìn)行操作,一個(gè)線程要和另外一個(gè)線程通信挪鹏,只能通過主存進(jìn)行交換见秽。
JMM可以說是Java并發(fā)的基礎(chǔ),它的定義將直接影響多線程實(shí)現(xiàn)的機(jī)制讨盒,如果你想要想深入了解多線程并發(fā)中的相關(guān)問題現(xiàn)象解取,對(duì)JMM的深入研究是必不可少的。
上面兩個(gè)問題是經(jīng)常容易搞混的返顺,但它們的內(nèi)容卻完全不同的禀苦。
3、JVM垃圾回收時(shí)候如何確定垃圾遂鹊?什么是GC Roots振乏?
JVM采用的是可達(dá)性分析算法。JVM是通過GC Roots來判定對(duì)象的存活的秉扑。從GC Roots
向下追溯慧邮、搜索,會(huì)產(chǎn)生一個(gè)叫做Reference Chain
的鏈條舟陆。當(dāng)一個(gè)對(duì)象不能和任何一個(gè)GC Root產(chǎn)生關(guān)系误澳,就判定為垃圾。
GC Roots大體包括:
- 活動(dòng)線程相關(guān)的各種引用秦躯,比如虛擬機(jī)棧中棧幀里的引用忆谓。
- 類的靜態(tài)變量的引用。
- JNI引用等踱承。
當(dāng)然也有比較詳細(xì)的回答倡缠,個(gè)人認(rèn)為這些就夠了哨免。詳細(xì)版本如下:
- Java線程中,當(dāng)前所有正在被調(diào)用的方法的
引用類型
參數(shù)昙沦、局部變量琢唾、臨時(shí)值等。也就是與我們棧幀
相關(guān)的各種引用桅滋。 - 所有當(dāng)前被加載的Java類慧耍。
- Java類的引用類型靜態(tài)變量身辨。
- 運(yùn)行時(shí)常量池里的引用類型常量(String或Class類型)丐谋。
- JVM內(nèi)部數(shù)據(jù)結(jié)構(gòu)的一些引用,比如
sun.jvm.hotspot.memory.Universe
類煌珊。 - 用于同步的監(jiān)控對(duì)象号俐,比如調(diào)用了對(duì)象的
wait()
方法。 - JNI handles定庵,包括global handles和local handles
4吏饿、能夠找到 Reference Chain 的對(duì)象,就一定會(huì)存活么蔬浙?
這不一定猪落,還要看reference類型。弱引用會(huì)在GC時(shí)會(huì)被回收畴博,軟引用會(huì)在內(nèi)存不足的時(shí)候被回收笨忌。但沒有Reference Chain的對(duì)象就一定會(huì)被回收。
5俱病、強(qiáng)引用官疲、軟引用、弱引用亮隙、虛引用是什么途凫?
普通的對(duì)象引用關(guān)系就是強(qiáng)引用。
軟引用用于維護(hù)一些可有可無的對(duì)象溢吻。只有在內(nèi)存不足時(shí)维费,系統(tǒng)則會(huì)回收軟引用對(duì)象,如果回收了軟引用對(duì)象之后仍然沒有足夠的內(nèi)存促王,才會(huì)拋出內(nèi)存溢出異常掩完。
弱引用對(duì)象相比較軟引用,要更加無用一些
硼砰,它擁有更短的生命周期且蓬。當(dāng)JVM進(jìn)行垃圾回收時(shí),無論內(nèi)存是否充足题翰,都會(huì)回收被弱引用關(guān)聯(lián)的對(duì)象恶阴。
虛引用是一種形同虛設(shè)的引用诈胜,在現(xiàn)實(shí)場景中用的不是很多,它主要用來跟蹤對(duì)象被垃圾回收的活動(dòng)冯事。
6焦匈、你說你做過JVM參數(shù)調(diào)優(yōu)和參數(shù)配置,請(qǐng)問如何查看JVM系統(tǒng)默認(rèn)值
使用-XX:+PrintFlagsFinal參數(shù)可以看到參數(shù)的默認(rèn)值昵仅。這個(gè)默認(rèn)值還和垃圾回收器有關(guān)缓熟,比如UseAdaptiveSizePolicy。
7摔笤、你平時(shí)工作中用過的JVM常用基本配置參數(shù)有哪些够滑?
Xmx
、Xms
吕世、Xmn
彰触、MetaspaceSize
等。
你只需要記憶10個(gè)左右即可應(yīng)付絕大多數(shù)
面試命辖,建議只記憶G1相關(guān)參數(shù)况毅。CMS這種既耗時(shí)間參數(shù)又多又被淘汰的東西,不看也罷尔艇。面試時(shí)間有限尔许,不會(huì)在這上面糾結(jié),除非你表現(xiàn)的太囂張了终娃。
8味廊、請(qǐng)你談?wù)剬?duì)OOM的認(rèn)識(shí)
OOM是非常嚴(yán)重的問題,除了程序計(jì)數(shù)器
尝抖,其他內(nèi)存區(qū)域都有溢出的風(fēng)險(xiǎn)毡们。和我們平常工作最密切的,就是堆溢出昧辽。另外衙熔,元空間在方法區(qū)內(nèi)容非常多的情況下也會(huì)溢出。還有就是棧溢出搅荞,這個(gè)通常影響比較小红氯。堆外也有溢出的可能,這個(gè)就比較難排查一些咕痛。
9痢甘、你都有哪些手段用來排查內(nèi)存溢出?
(這個(gè)話題很大茉贡,可以從實(shí)踐環(huán)節(jié)中隨便摘一個(gè)進(jìn)行總結(jié)塞栅,下面舉例一個(gè)最普通的)
你可以來一個(gè)中規(guī)中矩的回答:
內(nèi)存溢出包含很多種情況,我在平常工作中遇到最多的就是堆溢出
腔丧。有一次線上遇到故障放椰,重新啟動(dòng)后作烟,使用jstat命令,發(fā)現(xiàn)Old區(qū)在一直增長砾医。我使用jmap命令拿撩,導(dǎo)出了一份線上堆棧,然后使用MAT
進(jìn)行分析如蚜。通過對(duì)GC Roots
的分析压恒,我發(fā)現(xiàn)了一個(gè)非常大的HashMap對(duì)象,這個(gè)原本是有位同學(xué)做緩存
用的错邦,但是一個(gè)無界緩存探赫,造成了堆內(nèi)存占用一直上升。后來兴猩,將這個(gè)緩存改成 guava的Cache期吓,并設(shè)置了弱引用早歇,故障就消失了倾芝。
這個(gè)回答不是十分出彩,但著實(shí)是常見問題箭跳,讓人挑不出毛病晨另。
10、GC垃圾回收算法與垃圾收集器的關(guān)系谱姓?
常用的垃圾回收算法有標(biāo)記清除借尿、標(biāo)記整理、復(fù)制算法等屉来。引用計(jì)數(shù)器也算是一種路翻,但是沒有垃圾回收器使用這種算法,因?yàn)橛醒h(huán)依賴的問題茄靠。
很多垃圾回收器都是分代回收的茂契。對(duì)于年輕代,主要有Serial慨绳、ParNew等垃圾回收器掉冶,回收過程主要使用復(fù)制算法。
老年代的回收算法有Serial脐雪、CMS等厌小,主要使用標(biāo)記清除、標(biāo)記整理算法等战秋。
我們線上用的較多的是G1璧亚,也有年輕代和老年代的概念,不過它是一個(gè)整堆回收器脂信,它的回收對(duì)象是小堆區(qū) 癣蟋。
在目前G1大行其道的今天拐袜,實(shí)在沒必要再糾結(jié)CMS這么難用的東西了。
11梢薪、生產(chǎn)上如何配置垃圾收集器的蹬铺?
首先是內(nèi)存大小問題,基本上每一個(gè)內(nèi)存區(qū)域我都會(huì)設(shè)置一個(gè)上限秉撇,來避免溢出問題甜攀,比如元空間渗鬼。通常凡橱,堆空間我會(huì)設(shè)置成操作系統(tǒng)的2/3
(這是想給其他進(jìn)程和操作系統(tǒng)預(yù)留一些時(shí)間),超過8GB的堆優(yōu)先選用G1衷咽。
接下來瘦麸,我會(huì)對(duì)JVM進(jìn)行初步優(yōu)化谁撼。比如根據(jù)老年代的對(duì)象提升速度,來調(diào)整年輕代和老年代之間的比例滋饲。
再接下來厉碟,就是專項(xiàng)優(yōu)化,主要判斷的依據(jù)就是系統(tǒng)容量屠缭、訪問延遲箍鼓、吞吐量等。我們的服務(wù)是高并發(fā)的呵曹,所以對(duì)STW的時(shí)間非常敏感款咖。
我會(huì)通過記錄詳細(xì)的GC日志,來找到這個(gè)瓶頸點(diǎn)奄喂,借用gceasy
(重點(diǎn))這樣的日志分析工具铐殃,很容易定位到問題。之所以選擇采用工具跨新,是因?yàn)間c日志看起來實(shí)在是太麻煩了富腊,gceasy號(hào)稱是AI學(xué)習(xí)分析問題,可視化做的較好玻蝌。
12蟹肘、怎么查看服務(wù)器默認(rèn)的垃圾回收器是哪一個(gè)?
這通常會(huì)使用另外一個(gè)參數(shù):-XX:+PrintCommandLineFlags
可以打印所有的參數(shù)俯树,包括使用的垃圾回收器帘腹。
13、假如生產(chǎn)環(huán)境CPU占用過高许饿,請(qǐng)談?wù)勀愕姆治鏊悸泛投ㄎ弧?/h3>
圖片
這個(gè)可真是太太太常見了阳欲,不過已經(jīng)爛大街了。如果你還是一個(gè)有經(jīng)驗(yàn)的開發(fā)者,不知道的話球化,需要反省一下了秽晚。
首先,使用top -H
命令獲取占用CPU最高的線程筒愚,并將它轉(zhuǎn)化為16進(jìn)制赴蝇。
然后,使用jstack
命令獲取應(yīng)用的棧信息巢掺,搜索這個(gè)16進(jìn)制句伶。這樣能夠方便的找到引起CPU占用過高的具體原因。
如果有條件的話陆淀,直接使用arthas
就行操作就好了考余,不用再做這些費(fèi)事費(fèi)力的操作。
14轧苫、對(duì)于JDK自帶的監(jiān)控和性能分析工具用過哪些楚堤?
jps
:用來顯示Java進(jìn)程;jstat
:用來查看GC含懊;jmap
:用來dump堆身冬;jstack
:用來dump棧;jhsdb
:用來查看執(zhí)行中的內(nèi)存信息绢要;
都是非常常用的工具吏恭,要熟練掌握拗小。因?yàn)榫€上環(huán)境通常都有很多限制重罪,用不了圖形化工具。當(dāng)出現(xiàn)這些情況哀九,上面的命令就是救命的剿配。
15、棧幀都有哪些數(shù)據(jù)阅束?
JVM的運(yùn)行是基于棧的呼胚,和C語言的棧類似,它的大多數(shù)數(shù)據(jù)都是在堆里面的息裸,只有少部分運(yùn)行時(shí)的數(shù)據(jù)存在于棧上蝇更。
在JVM中,每個(gè)線程棧里面的元素呼盆,就叫棧幀
年扩。
棧幀包含:局部變量表、操作數(shù)棧访圃、動(dòng)態(tài)連接厨幻、返回地址等。
16、JIT是什么况脆?
為了提高熱點(diǎn)代碼的執(zhí)行效率饭宾,在運(yùn)行時(shí),虛擬機(jī)將會(huì)把這些代碼編譯成與本地平臺(tái)相關(guān)的機(jī)器碼格了,并進(jìn)行各種層次的優(yōu)化看铆。完成這個(gè)任務(wù)的編譯器,就稱為即時(shí)編譯器(Just In Time Compiler)盛末,簡稱 JIT 編譯器性湿。
17、Java的雙親委托機(jī)制是什么满败?
它的意思是肤频,除了頂層的啟動(dòng)類加載器以外,其余的類加載器算墨,在加載之前宵荒,都會(huì)委派給它的父加載器進(jìn)行加載。這樣一層層向上傳遞净嘀,直到祖先們都無法勝任报咳,它才會(huì)真正的加載。
Java默認(rèn)是這種行為挖藏。當(dāng)然Java中也有很多打破雙親行為的騷操作暑刃,比如SPI(JDBC驅(qū)動(dòng)加載),OSGI等膜眠。
18岩臣、有哪些打破了雙親委托機(jī)制的案例?
- Tomcat可以加載自己目錄下的class文件宵膨,并不會(huì)傳遞給父類的加載器架谎。
- Java的SPI,發(fā)起者是
BootstrapClassLoader
辟躏,BootstrapClassLoader
已經(jīng)是最上層的了谷扣。它直接獲取了AppClassLoader
進(jìn)行驅(qū)動(dòng)加載,和雙親委派是相反的捎琐。会涎。
19、簡單描述一下(分代)垃圾回收的過程
分代回收器有兩個(gè)分區(qū):老生代和新生代瑞凑,新生代默認(rèn)的空間占比總空間的 1/3
末秃,老生代的默認(rèn)占比是 2/3
。
新生代使用的是復(fù)制算法拨黔,新生代里有 3 個(gè)分區(qū):Eden
蛔溃、To Survivor
绰沥、From Survivor
,它們的默認(rèn)占比是 8:1:1
贺待,它的執(zhí)行流程如下:
當(dāng)年輕代中的Eden區(qū)分配滿的時(shí)候徽曲,就會(huì)觸發(fā)年輕代的GC(Minor GC)。具體過程如下:
- 在Eden區(qū)執(zhí)行了
第一次
GC之后麸塞,存活的對(duì)象會(huì)被移動(dòng)到其中一個(gè)Survivor分區(qū)(以下簡稱from) - Eden區(qū)再次GC秃臣,這時(shí)會(huì)采用復(fù)制算法,將Eden和from區(qū)一起清理哪工。存活的對(duì)象會(huì)被復(fù)制到to區(qū)奥此。接下來,只需要清空from區(qū)就可以了
20雁比、CMS分為哪幾個(gè)階段?
CMS已經(jīng)棄用稚虎。生活美好,時(shí)間有限偎捎,不建議再深入研究了蠢终。如果碰到問題,直接祭出回收過程即可茴她。
(1)初始標(biāo)記 (2)并發(fā)標(biāo)記 (3)并發(fā)預(yù)清理 (4)并發(fā)可取消的預(yù)清理 (5)重新標(biāo)記 (6)并發(fā)清理
由于《深入理解java虛擬機(jī)》一書的流行寻拂,面試時(shí)省略3、4步一般也是沒問題的丈牢。
21祭钉、CMS都有哪些問題?
(1)內(nèi)存碎片問題己沛。Full GC的整理階段慌核,會(huì)造成較長時(shí)間的停頓。(2)需要預(yù)留空間泛粹,用來分配收集階段產(chǎn)生的“浮動(dòng)垃圾“遂铡。(3)使用更多的CPU資源,在應(yīng)用運(yùn)行的同時(shí)進(jìn)行堆掃描晶姊。(4)停頓時(shí)間是不可預(yù)期的。
正因?yàn)橛羞@些問題伪货,所以大家才用更加完備的G1们衙。況且,現(xiàn)在都是大內(nèi)存時(shí)代了碱呼,G1玩得轉(zhuǎn)蒙挑,就沒必要用CMS。
22愚臀、你都用過G1垃圾回收器的哪幾個(gè)重要參數(shù)忆蚀?
最重要的是MaxGCPauseMillis
,可以通過它設(shè)定G1的目標(biāo)停頓時(shí)間,它會(huì)盡量的去達(dá)成這個(gè)目標(biāo)馋袜。G1HeapRegionSize可以設(shè)置小堆區(qū)的大小男旗,一般是2的次冪。
InitiatingHeapOccupancyPercent
欣鳖,啟動(dòng)并發(fā)GC時(shí)的堆內(nèi)存占用百分比察皇。G1用它來觸發(fā)并發(fā)GC周期,基于整個(gè)堆的使用率泽台,而不只是某一代內(nèi)存的使用比例什荣,默認(rèn)是45%。
再多怀酷?不是專家稻爬,就沒必要要求別人也是。
23蜕依、GC日志的real因篇、user、sys是什么意思笔横?
real
實(shí)際花費(fèi)的時(shí)間竞滓,指的是從開始到結(jié)束所花費(fèi)的時(shí)間。比如進(jìn)程在等待I/O完成吹缔,這個(gè)阻塞時(shí)間也會(huì)被計(jì)算在內(nèi)商佑。user
指的是進(jìn)程在用戶態(tài)(User Mode)所花費(fèi)的時(shí)間,只統(tǒng)計(jì)本進(jìn)程所使用的時(shí)間厢塘,是指多核茶没。sys
指的是進(jìn)程在核心態(tài)(Kernel Mode)花費(fèi)的CPU時(shí)間量,指的是內(nèi)核中的系統(tǒng)調(diào)用所花費(fèi)的時(shí)間晚碾,只統(tǒng)計(jì)本進(jìn)程所使用的時(shí)間抓半。
這個(gè)是用來看日志用的,如果你不看日志格嘁,那不了解也無妨笛求。不過,這三個(gè)參數(shù)的意義糕簿,在你能看到的地方探入,基本上都是一致的,比如操作系統(tǒng)懂诗。
24蜂嗽、什么情況會(huì)造成元空間溢出?
元空間(Metaspace)默認(rèn)是沒有上限的殃恒,不加限制比較危險(xiǎn)植旧。當(dāng)應(yīng)用中的Java類過多辱揭,比如Spring等一些使用動(dòng)態(tài)代理的框架生成了很多類,如果占用空間超出了我們的設(shè)定值
病附,就會(huì)發(fā)生元空間溢出问窃。
所以,默認(rèn)風(fēng)險(xiǎn)大胖喳,但如果你不給足它空間泡躯,它也會(huì)溢出。
25丽焊、什么時(shí)候會(huì)造成堆外內(nèi)存溢出较剃?
使用了Unsafe類申請(qǐng)內(nèi)存,或者使用了JNI對(duì)內(nèi)存進(jìn)行操作技健。這部分內(nèi)存是不受JVM控制的写穴,不加限制的使用,容易發(fā)生內(nèi)存溢出雌贱。
26啊送、SWAP會(huì)影響性能么?
當(dāng)操作系統(tǒng)內(nèi)存不足的時(shí)候欣孤,會(huì)將部分?jǐn)?shù)據(jù)寫入到SWAP交換分中馋没,但是SWAP的性能是比較低的。如果應(yīng)用的訪問量較大降传,需要頻繁申請(qǐng)和銷毀內(nèi)存篷朵,就容易發(fā)生卡頓。一般高并發(fā)場景下婆排,會(huì)禁用SWAP声旺。
27、有什么堆外內(nèi)存的排查思路段只?
進(jìn)程占用的內(nèi)存腮猖,可以使用top命令,看RES段占用的值赞枕。如果這個(gè)值大大超出我們設(shè)定的最大堆內(nèi)存澈缺,則證明堆外內(nèi)存占用了很大的區(qū)域。
使用gdb可以將物理內(nèi)存dump下來鹦赎,通常能看到里面的內(nèi)容谍椅。更加復(fù)雜的分析可以使用perf工具,或者谷歌開源的gperftools古话。那些申請(qǐng)內(nèi)存最多的native函數(shù),很容易就可以找到锁施。
28陪踩、HashMap中的key杖们,可以是普通對(duì)象么?需要什么注意的地方肩狂?
Map的key和value都可以是任何類型摘完。但要注意的是,一定要重寫它的equals和hashCode方法傻谁,否則容易發(fā)生內(nèi)存泄漏孝治。
29、怎么看死鎖的線程审磁?
通過jstack命令谈飒,可以獲得線程的棧信息。死鎖信息會(huì)在非常明顯的位置(一般是最后)進(jìn)行提示态蒂。
30杭措、如何寫一段簡單的死鎖代碼?
這個(gè)筆試的話頻率也挺高(遇見筆試的公司要三思凹鼗帧)手素,所以這里直接給出一個(gè)答案(有很多版本的)。
public class DeadLockDemo { public static void main(String[] args) { Object object1 = new Object(); Object object2 = new Object(); Thread t1 = new Thread(() -> { synchronized (object1) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (object2) { } } }, "deadlock-demo-1"); t1.start(); Thread t2 = new Thread(() -> { synchronized (object2) { synchronized (object1) { } } }, "deadlock-demo-2"); t2.start(); }}
31瘩蚪、invokedynamic指令是干什么的泉懦?
屬于比較高級(jí)的題目。沒看過虛擬機(jī)的一般是不知道的疹瘦。所以如果你不太熟悉崩哩,不要?dú)怵H,加油9敖浮(小拳拳錘你胸口)琢锋。
invokedynamic
是Java7
之后新加入的字節(jié)碼指令,使用它可以實(shí)現(xiàn)一些動(dòng)態(tài)類型語言的功能呢灶。我們使用的Lambda表達(dá)式吴超,在字節(jié)碼上就是invokedynamic指令實(shí)現(xiàn)的。它的功能有點(diǎn)類似反射鸯乃,但它是使用方法句柄實(shí)現(xiàn)的鲸阻,執(zhí)行效率更高。
32缨睡、volatile關(guān)鍵字的原理是什么鸟悴?干什么用的?
使用了volatile關(guān)鍵字的變量奖年,每當(dāng)變量的值有變動(dòng)的時(shí)候细诸,都會(huì)將更改立即同步到主內(nèi)存中;而如果某個(gè)線程想要使用這個(gè)變量陋守,就先要從主存中刷新到工作內(nèi)存震贵,這樣就確保了變量的可見性利赋。
一般使用一個(gè)volatile修飾的bool變量,來控制線程的運(yùn)行狀態(tài)猩系。
volatile boolean stop = false; void stop(){ this.stop = true; } void start(){ new Thread(()->{ while (!stop){ //sth } }).start(); }
33媚送、什么是方法內(nèi)聯(lián)?
為了減少方法調(diào)用的開銷寇甸,可以把一些短小的方法塘偎,比如getter/setter
,納入到目標(biāo)方法的調(diào)用范圍之內(nèi)拿霉,就少了一次方法調(diào)用吟秩,速度就能得到提升,這就是方法內(nèi)聯(lián)的概念友浸。
34峰尝、對(duì)象是怎么從年輕代進(jìn)入老年代的?
這是老掉牙的題目了收恢。在下面四種情況下武学,對(duì)象會(huì)從年輕代進(jìn)入老年代。
- 如果對(duì)象夠老伦意,會(huì)通過提升(Promotion)進(jìn)入老年代火窒,這一般是根據(jù)對(duì)象的年齡進(jìn)行判斷的。
- 動(dòng)態(tài)對(duì)象年齡判定驮肉。有的垃圾回收算法熏矿,比如G1,并不要求age必須達(dá)到15才能晉升到老年代离钝,它會(huì)使用一些動(dòng)態(tài)的計(jì)算方法票编。
- 分配擔(dān)保。當(dāng) Survivor 空間不夠的時(shí)候卵渴,就需要依賴其他內(nèi)存(指老年代)進(jìn)行分配擔(dān)保慧域。這個(gè)時(shí)候,對(duì)象也會(huì)直接在老年代上分配浪读。
- 超出某個(gè)大小的對(duì)象將直接在老年代分配昔榴。不過這個(gè)值默認(rèn)為0,意思是全部首選Eden區(qū)進(jìn)行分配碘橘。
35互订、safepoint是什么?
STW并不會(huì)只發(fā)生在內(nèi)存回收的時(shí)候《徊穑現(xiàn)在程序員這么卷仰禽,碰到幾次safepoint的問題幾率也是比較大的。
當(dāng)發(fā)生GC時(shí),用戶線程必須全部停下來坟瓢,才可以進(jìn)行垃圾回收勇边,這個(gè)狀態(tài)我們可以認(rèn)為JVM是安全的(safe)犹撒,整個(gè)堆的狀態(tài)是穩(wěn)定的折联。
如果在GC前,有線程遲遲進(jìn)入不了safepoint识颊,那么整個(gè)JVM都在等待這個(gè)阻塞的線程诚镰,造成了整體GC的時(shí)間變長。
36祥款、MinorGC清笨,MajorGC、FullGC都什么時(shí)候發(fā)生刃跛?
MinorGC在年輕代空間不足的時(shí)候發(fā)生抠艾,MajorGC指的是老年代的GC,出現(xiàn)MajorGC一般經(jīng)常伴有MinorGC桨昙。
FullGC有三種情況检号。
- 當(dāng)老年代無法再分配內(nèi)存的時(shí)候
- 元空間不足的時(shí)候
- 顯示調(diào)用System.gc的時(shí)候。另外蛙酪,像CMS一類的垃圾回收器齐苛,在MinorGC出現(xiàn)promotion failure的時(shí)候也會(huì)發(fā)生FullGC
37、類加載有幾個(gè)過程桂塞?
加載凹蜂、驗(yàn)證、準(zhǔn)備阁危、解析玛痊、初始化。
38狂打、什么情況下會(huì)發(fā)生棧溢出擂煞?
棧的大小可以通過-Xss參數(shù)進(jìn)行設(shè)置,當(dāng)遞歸層次太深的時(shí)候菱父,就會(huì)發(fā)生棧溢出颈娜。比如循環(huán)調(diào)用,遞歸等浙宜。