1.1 Java棧
線程私有,生命周期與線程相同言秸。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表软能、操作數(shù)棧、動(dòng)態(tài)鏈接举畸、方法出口等信息查排。每個(gè)方法從調(diào)用直至執(zhí)行完成的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過程抄沮。如果請(qǐng)求的站深度大于虛擬機(jī)所允許的深度跋核,將拋出StackOverflowError異常,虛擬機(jī)棧在動(dòng)態(tài)擴(kuò)展時(shí)如果無法申請(qǐng)到足夠的內(nèi)存叛买,就會(huì)拋出OutOfMemoryError異常砂代。
總結(jié):它存放的是java方法執(zhí)行時(shí)的所有數(shù)據(jù)。 由棧幀組成一個(gè)棧幀代表一個(gè)方法的執(zhí)行率挣。
Java棧幀
每個(gè)方法從調(diào)用到執(zhí)行完成對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)中的入棧到出棧刻伊。
結(jié)構(gòu)圖:
棧幀由局部變量區(qū)、操作數(shù)棧和幀數(shù)據(jù)區(qū)組成椒功。當(dāng)虛擬機(jī)調(diào)用一個(gè)Java方法時(shí),它從對(duì)應(yīng)類的類型信息中得到此方法的局部變量區(qū)和操作數(shù)棧的大小丁屎,并根據(jù)此分配棧幀內(nèi)存旱眯,然后壓入Java棧中节沦。
例如:
public static String A(){
String str=B();(1)
return str;
}
public static String B(){
return "Hellow Word";
}
A方法執(zhí)行時(shí)分配一個(gè)棧幀,當(dāng)(1)處調(diào)用B方法是就會(huì)壓如一個(gè)新的棧幀吼鳞,當(dāng)B()方法結(jié)束赔桌,棧幀彈出。
-
局部變量區(qū)
局部變量區(qū)被組織為以字長為單位音诫、從0開始計(jì)數(shù)的數(shù)組竭钝。字節(jié)碼指令通過從0開始的索引使用其中的數(shù)據(jù)香罐。類型為int, float, reference和returnAddress的值在數(shù)組中占據(jù)一項(xiàng)庇茫,而類型為byte, short和char的值在存入數(shù)組前都被轉(zhuǎn)換為int值旦签,也占據(jù)一項(xiàng)寸宏。但類型為long和double的值在數(shù)組中卻占據(jù)連續(xù)的兩項(xiàng)击吱。
returnAddress這個(gè)基本類型被用來實(shí)現(xiàn)Java程序中的finally子句覆醇,Java程序員不能使用這個(gè)類型,它的值指向一條虛擬機(jī)指令的操作碼袍辞。
結(jié)構(gòu)圖:
操作數(shù)棧
和局部變量區(qū)一樣搅吁,操作數(shù)棧也是被組織成一個(gè)以字長為單位的數(shù)組谎懦。它通過標(biāo)準(zhǔn)的棧操作訪問--壓棧和出棧。由于程序計(jì)數(shù)器無法被程序指令直接訪問吸申,Java虛擬機(jī)的指令是從操作數(shù)棧中取得操作數(shù)截碴,所以它的運(yùn)行方式是基于棧而不是基于寄存器日丹。虛擬機(jī)把操作數(shù)棧作為它的工作區(qū)哲虾,因?yàn)榇蠖鄶?shù)指令都要從這里彈出數(shù)據(jù)齐帚,執(zhí)行運(yùn)算对妄,然后把結(jié)果壓回操作數(shù)棧剪菱。
1.2 本地方法棧
與虛擬機(jī)棧類似,不過虛擬機(jī)棧是為虛擬機(jī)執(zhí)行Java方法(字節(jié)碼)服務(wù)旗们,而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)上渴。該區(qū)域同樣會(huì)報(bào)StackOverflowError
方法區(qū)
1.3 方法區(qū)
用于存儲(chǔ)被Java虛擬機(jī)加載的類信息稠氮、常量隔披、靜態(tài)變量寂拆、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。不同于Java堆的是鬓长,Java虛擬機(jī)規(guī)范對(duì)方法區(qū)的限制非常寬松痢士,可以選擇不實(shí)現(xiàn)垃圾收集(永遠(yuǎn)占據(jù)內(nèi)存)。
常量池:這個(gè)名詞可能大家也經(jīng)常見,它是方法區(qū)的一部分城侧。Class文件除了有類的版本嫌佑、字段侨歉、方法幽邓、接口等描述信息外,還有一項(xiàng)信息就是常量池柒啤,用于存放編譯期生成的各種字面量和符號(hào)引用担巩。(JDK1.7已經(jīng)把常量池轉(zhuǎn)移到堆里面了)
1.4 堆區(qū)
所有通過new對(duì)象的內(nèi)存都在對(duì)中分配;是虛擬機(jī)最大一塊內(nèi)存涛癌,是要GC回收的拳话。這一部分也是重點(diǎn)需要分析的漾脂。
1.5 程序計(jì)數(shù)器
一塊較小的內(nèi)存空間骨稿,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令形耗,分支激涤、循環(huán)、跳轉(zhuǎn)送滞、異常處理犁嗅、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器完成褂微。此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域宠蚂。(也就是說明其他區(qū)域都可能產(chǎn)生OOM童社,但是我們開發(fā)中重點(diǎn)是根據(jù)堆的原理避免OOM)
2.Java堆區(qū)分析
Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊叠洗,被進(jìn)程的所有線程共享,在虛擬機(jī)啟動(dòng)時(shí)被創(chuàng)建十艾。該區(qū)域的唯一目的就是存放對(duì)象實(shí)例忘嫉,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存庆冕,Java堆是垃圾收集器管理的主要區(qū)域访递。根據(jù)Java虛擬機(jī)規(guī)范同辣,Java堆可以處于物理上不連續(xù)的內(nèi)存空間,只要邏輯上連續(xù)即可响巢。該區(qū)域的大小可以通過-Xmx和-Xms參數(shù)來擴(kuò)展(這部分不懂)踪古,如果堆中沒有內(nèi)存完成實(shí)例分配伏穆,并且堆也無法擴(kuò)展,將會(huì)拋出OutOfMemoryError異常田弥。
2.1 堆區(qū)內(nèi)存
由于現(xiàn)在的收集器基本都采用分代收集算法,所以Java堆中還可以分為老年代和新生代(Eden商叹、From Survivor剖笙、To Survivor)
(一般服務(wù)器需要修改 移動(dòng)端不太需要修改)
3. 垃圾回收原理
3.1 垃圾收集算法
3.1.1 引用計(jì)數(shù)算法(jdk1.2以前)
引用計(jì)數(shù)算法只要可達(dá) 有被引用就+1 就不會(huì)被回收
3.1.2 引用計(jì)數(shù)算法(下面幾種都是jdk1.2以后)
之間的連線關(guān)系是通過引用來實(shí)現(xiàn)關(guān)聯(lián)的过蹂。
既然提到了引用不得不提四大引用類型:
這部分我一直沒有找到比較好的文章,自己本身也理解不好脆诉。后期有機(jī)會(huì)會(huì)找找書籍與實(shí)踐好好研究下另寫文章贷币。
參考1
參考2
3.2 垃圾回收算法
通過收集算法役纹。將垃圾對(duì)象回收J(rèn)VN虛擬機(jī)也是用過一些算法進(jìn)行處理掉垃圾的。
3.2.1 標(biāo)記-清楚算法
3.2.1 復(fù)制算法
3.2.1 標(biāo)記整理算法
標(biāo)記整理算法是對(duì)標(biāo)記-清楚算法做了一些調(diào)整策州,當(dāng)掃描到不被引用的對(duì)象的時(shí)候 它和標(biāo)記-清除算法一樣會(huì)移除抽活,但是它會(huì)將所有存活的對(duì)象向左移動(dòng)并更新指針 因?yàn)橐苿?dòng)對(duì)象并更新指針 所以成本更高锰什,但是解決了內(nèi)存碎片的問題
總結(jié) :
這三種算法是根據(jù)實(shí)際情況在虛擬機(jī)中結(jié)合使用的梭姓。并不知道單一使用
根據(jù)不同的優(yōu)缺點(diǎn)與場(chǎng)景JVM會(huì)通過運(yùn)算來決定使用哪種嫩码。
3.3 觸發(fā)回收
手動(dòng)調(diào)用虛擬機(jī)也不會(huì)馬上執(zhí)行铸题,它也是會(huì)等到合適的時(shí)機(jī)進(jìn)行內(nèi)存回收丢间。但是調(diào)用System.gc()會(huì)增到虛擬機(jī)的壓力。