這個(gè)文章是自己看書記錄用于以后復(fù)習(xí)用的,不適用于大家學(xué)習(xí)海洼,如果不小心搜索到,那現(xiàn)在可以直接關(guān)閉了
面試題收集:
1背稼、你知道哪些或者你們線上使?什么GC策略贰军?它有什么優(yōu)勢,適?于什么場景蟹肘?
2词疼、Java類加載器包括?種?它們之間的??關(guān)系是怎么樣的帘腹?雙親委派機(jī)制是什么意思贰盗?有什么好處?
3阳欲、如何?定義?個(gè)類加載器舵盈?你使?過哪些或者你在什么場景下需要?個(gè)?定義的類加載器嗎?
4球化、堆內(nèi)存設(shè)置的參數(shù)是什么秽晚?
5、Perm Space中保存什么數(shù)據(jù)筒愚?會引起OutOfMemory嗎赴蝇?
6、做GC時(shí)巢掺,?個(gè)對象在內(nèi)存各個(gè)Space中被移動(dòng)的順序是什么句伶?
7、你有沒有遇到過OutOfMemory問題陆淀?你是怎么來處理這個(gè)問題的考余?處理 過程中有哪些收獲?
8轧苫、JDK 1.8之后Perm Space有哪些變動(dòng)? MetaSpace??默認(rèn)是?限的么? 還是你們會通過什么?式來指定???
9楚堤、jstack 是?什么的? jstat 呢?如果線上程序周期性地出現(xiàn)卡頓含懊,你懷疑可 能是 GC 導(dǎo)致的钾军,你會怎么來排查這個(gè)問題?線程?志?般你會看其中的什么 部分绢要?
10吏恭、StackOverflow異常有沒有遇到過??般你猜測會在什么情況下被觸發(fā)重罪?如何指定?個(gè)線程的堆棧??樱哼??般你們寫多少哀九?
一 運(yùn)行時(shí)數(shù)據(jù)區(qū)域
1.1.1 程序計(jì)數(shù)器
線程私有,用于記錄當(dāng)前線程運(yùn)行到的位置搅幅,以便隨時(shí)恢復(fù)線程
1.1.2 Java虛擬機(jī)棧
線程私有阅束,包括棧幀,局部變量表茄唐,操作數(shù)棧息裸,動(dòng)態(tài)鏈接,方法出口
局部變量表保存8種基本類型的局部變量沪编,以及引用類型的指針
棧幀對應(yīng)著一個(gè)方法
1.1.3 本地方法棧
與Java虛擬機(jī)棧類似呼盆,但是是用于支持native方法的執(zhí)行的,在hotspot虛擬機(jī)中蚁廓,Java虛擬機(jī)棧與本地方法棧共用
1.1.4 Java 堆
所有線程共享访圃,垃圾收集器的主要區(qū)域,可以分為新生代和老年代相嵌,新生代又分為Eden space, From survivor space , To survivor space腿时。
從內(nèi)存分配的角度看,可以分為多個(gè)線程私有的的分配緩沖區(qū)
通過-Xmx -Xms 控制大小
1.1.5 方法區(qū)
存放類信息饭宾,常量批糟,靜態(tài)變量,即時(shí)編譯器編譯后的代碼等數(shù)據(jù)
--XX:MaxPermSize 指定上限
這一區(qū)域的垃圾回收目標(biāo)主要是針對常量池的回收和類型的卸載
1.1.6 運(yùn)行時(shí)常量池
這是方法區(qū)的一部分看铆,用于存放編譯期生成的各種字面量和符號引用
1.1.7 對象的創(chuàng)建
- 檢查new指令的參數(shù)是否能在常量池中定位到一個(gè)類的符號引用跃赚,并且檢查類是否已經(jīng)被加載
- 為新生對象分配內(nèi)存空間
指針碰撞:java堆規(guī)整,Serial性湿,ParNew等帶Compact過程的收集器使用
空閑列表:java堆不規(guī)整,需要維護(hù)列表满败,CMS等Mark-Sweep算法收集器使用
如何保證內(nèi)存分配的原子性:
方法一:CAS+失敗重試的方法
方法二:使用-XX:+/-UseTABLE來指定使用本地線程分配緩沖
1.1.8 對象的內(nèi)存布局
對象在內(nèi)存中可以分為:對象頭(Header)實(shí)例數(shù)據(jù)(Instance Data)和對齊填充(Padding)
對象頭(儲存對象自身的運(yùn)行時(shí)數(shù)據(jù)):哈希碼肤频,GC分代年齡,鎖狀態(tài)標(biāo)志算墨,線程持有的鎖宵荒,偏向線程ID,偏向時(shí)間戳净嘀,類型指針(有的虛擬機(jī)可能沒有)报咳,如果是數(shù)據(jù)對象,還要記錄長度
實(shí)例數(shù)據(jù):默認(rèn)分配策略會把同大小的分配到一起挖藏,父類的變量會出現(xiàn)在子類之前暑刃,但是子類中較窄的變量也可能會插入到父類的間隙中去。
對齊填充:HotSpot VM 要求對象的起始地址必須是8字節(jié)的整數(shù)倍膜眠,所有要填充
1.1.9 對象的訪問定位
句柄訪問:java堆中劃分一塊內(nèi)存來作為句柄池岩臣,reference保存的是句柄池的地址溜嗜,句柄池中包含對象的實(shí)例數(shù)據(jù)指針和對象的類型指針。缺點(diǎn)是多一次訪問架谎,優(yōu)點(diǎn)是reference不用變炸宵。
直接指針訪問:reference直接保存對象實(shí)例數(shù)據(jù)地址,對象頭中包含元類型數(shù)據(jù)地址
HotSpot使用的是直接訪問的方式
二 垃圾收集器與內(nèi)存分配策略
2.1 對象已經(jīng)死了嗎
引用計(jì)數(shù)法
可達(dá)性分析算法:GC Roots 包括虛擬機(jī)棧中引用的對象谷扣、方法區(qū)中類靜態(tài)屬性引用的對象土全、方法區(qū)中常量引用的對象、本地方法棧中JNI引用的對象
2.2 引用類型
強(qiáng)引用:普通new Object()產(chǎn)生的引用
軟引用:內(nèi)存溢出時(shí)會回收
弱引用:下次GC時(shí)一定會回收
虛引用:無法通過虛引用來找到一個(gè)對象会涎,這種引用只是想在對象回收時(shí)收到一個(gè)通知
2.3 finalize()方法
對象第一次可達(dá)性分析裹匙,如果沒有與GC ROOTs相連,則會調(diào)用finalize方法在塔,在finalize方法中可以自救幻件,但是finalize方法只會被調(diào)用一次
2.4 回收方法區(qū)
方法區(qū)回收的效果不好,主要是回收廢棄常量和無用的類
廢棄常量:與堆中的對象類似蛔溃,沒有任何引用的對象
無用的類:必須要滿足以下三個(gè)條件绰沥,才會被回收
- 該類的實(shí)例已經(jīng)全被回收
- 加載該類的ClassLoader已經(jīng)被回收
- 該類的Class對象被回收
參數(shù)-Xnoclassgc 參數(shù)可以控制是否回收無用的類
2.5 垃圾回收算法
標(biāo)記清除法(Mark-Sweep):算法分為標(biāo)記-清除兩個(gè)階段
- 效率不高
- 容易產(chǎn)生碎片
復(fù)制算法:每次只用一塊,用完時(shí)把對象復(fù)制到另一塊中
- 實(shí)際使用的內(nèi)存只有原來的一半
- HotSpot新生代Eden:Survivor = 8:1 需要老年代擔(dān)保
標(biāo)記整理算法(Mark-Compact): 先標(biāo)記贺待,然后把存活對象往一邊移動(dòng)
分代回收的思想:新生代使用復(fù)制算法徽曲,老年代使用標(biāo)記-清理或者標(biāo)記-整理算法
2.6 HotSpot 算法實(shí)現(xiàn)
2.6.1.Serial收集器
虛擬機(jī)在Client模式下新生代的默認(rèn)收集器,單線程麸塞,采用復(fù)制算法
2.6.2 ParNew收集器
與Serial收集器一樣秃臣,只是回收新生代時(shí)采用的是多線程
這是Server模式下新生代的首選收集器
-XX:SurvivorRatio:Eden區(qū):兩個(gè)Survivor區(qū) 的比值
-XX:ParallelGCThreads : 指定線程的數(shù)量
-XX:+UseParNewGC強(qiáng)制指定使用這種收集器
2.6.3 Parallel Scavenge 收集器
新生代收集器,與ParNew一樣使用的是復(fù)制算法哪工,多線程奥此,但是這個(gè)收集器的目標(biāo)是使垃圾收集的時(shí)間盡量短
-XX MaxGCPauseMillis:控制最大垃圾收集時(shí)間
-XX:GCTimeRatio:用來控制吞吐量
-XX:UseAdptiveSizePolicy:自動(dòng)調(diào)用新生代大小,Eden和Survivor區(qū)的比例
2.6.4 Serial Old 收集器
Serial 收集器的老年代版本雁比,單線程稚虎,使用標(biāo)記整理算法
2.6.5 Parallel Old 收集器
Parallel Scavenge 收集器的老年代版本,多線程偎捎,標(biāo)記-整理算法
2.6.5 CMS收集器
以最短停頓時(shí)間為目標(biāo)蠢终,標(biāo)記清除算法
步驟一:初始標(biāo)記:從GC Roots 遞歸找到所有存活對象
步驟二:并發(fā)標(biāo)記:GC Roots Tracing過程
步驟三:重新標(biāo)記:修正并發(fā)標(biāo)記期間的變動(dòng)
步驟四:并發(fā)清除:清除對象
只有初始標(biāo)記和重新標(biāo)記會暫停用戶線程
缺點(diǎn):
- 對CPU資源比較敏感、占用(CPU+3) / 4 的線程
- 無法處理浮動(dòng)垃圾(并發(fā)清理階段用戶線程新產(chǎn)生的垃圾)茴她,不能等到老年代幾乎滿了才運(yùn)行(默認(rèn)68%寻拂,-XX:CMSInitiatingOccupancyFraction設(shè)置閥值),可能會出現(xiàn)Concurrent Mode Failure丈牢、
- 有碎片問題 -XX:+UseCMSCompactAtFullCollection設(shè)置FullGC后整理碎片祭钉,-XX:CMSFullGCsBeforeCompation設(shè)置多少次不整理后就會整理一次
2.6.6 對象分配策略
- 優(yōu)先在Eden區(qū)分配
- 大對象直接進(jìn)入老年代: -XX:PretenureSizeThreshold 參數(shù)用于設(shè)置直接進(jìn)入老年代的閥值,這個(gè)參數(shù)只對Serial和ParNew收集器
- 長期存活對象進(jìn)入老年代:-XX: MaxTenuringThreshold參數(shù)設(shè)置進(jìn)入老年代的對象年齡
- 對象動(dòng)態(tài)年齡判斷:若則在某個(gè)年齡己沛,Survivor空間中相同年齡所有對象大小總和大于Survivor一半朴皆,則年齡大于或等于該的年齡的對象全進(jìn)入老年代
三 常用監(jiān)控分析工具
- jps:顯示指定系統(tǒng)內(nèi)所有的hotspot虛擬機(jī)進(jìn)程
- jstat:用于收集HotSpot虛擬機(jī)各方面的數(shù)據(jù)
- jinfo:顯示虛擬機(jī)配置信息
- jmap:生成虛擬機(jī)內(nèi)存轉(zhuǎn)儲快照文件
- jhat:用于分析headmap文件
- jstack:顯示虛擬機(jī)線程快照
3.1 jps
- -q:只輸出虛擬機(jī)ID帕识,忽略其他參數(shù)
- -m:輸出啟動(dòng)主類時(shí)傳遞給main的參數(shù)
- -l:輸出主類的全類名,如果執(zhí)行的是jar包遂铡,輸出jar包位置
- -v:輸出jvm參數(shù)