前言
JVM內(nèi)存模型: JVM就是java虛擬機(jī)褐荷,顧名思義腻菇,就是以軟件的方式模擬具有完整硬件系統(tǒng)功能作岖、運(yùn)行在一個(gè)完全隔離環(huán)境中的完整計(jì)算機(jī)系統(tǒng),是物理機(jī)器的軟件實(shí)現(xiàn)颂龙。綜上所述习蓬,JVM虛擬機(jī)是一個(gè)軟件纽什,它所在的結(jié)構(gòu)是處于下圖所示
一: JVM內(nèi)部由哪些組成
如下圖所示JVM主要由以下幾部分組成:
- 類裝載子系統(tǒng)
- 執(zhí)行引擎
- JVM內(nèi)存模型(本文主要講的是這個(gè))
PS:如圖所示措嵌,如果一個(gè)Math.class類要加載到JVM中需要經(jīng)過的步驟:類裝載子系統(tǒng)會(huì)把字節(jié)碼裝載到內(nèi)存區(qū)域躲叼,執(zhí)行引擎執(zhí)行程序
二:JVM內(nèi)存模型由哪幾部分組成
如下圖可知,JVM內(nèi)存模型分為線程私有和線程共有企巢,我們從這兩個(gè)角度分別展開說
2.1 線程私有
①:程序計(jì)數(shù)器:記錄字節(jié)碼行號(hào)枫慷,唯一不會(huì)產(chǎn)生內(nèi)存溢出的地方
②:java虛擬機(jī)棧:
當(dāng)java中的方法被執(zhí)行時(shí),會(huì)形成棧幀被放入棧內(nèi)存中浪规,這種行為稱為“壓椈蛱”
方法執(zhí)行完,棧內(nèi)存彈出笋婿,這個(gè)過程叫做”彈椨桑”
由下圖我們可以看到,棧幀包含:局部變量表缸濒、操作數(shù)棧足丢、方法出口,所以為什么我們平時(shí)說一個(gè)局部變量在方法執(zhí)行完畢之后庇配,就會(huì)在內(nèi)存中釋放斩跌,就是因?yàn)?strong>”彈棧”這個(gè)過程捞慌,局部變量表釋放了
③:本地方法棧:主要控制一些native方法的調(diào)用
2.2 線程共有
①:方法區(qū)(元數(shù)據(jù)區(qū)):類信息耀鸦、常量、靜態(tài)變量
ps1:我們剛才所說了一個(gè)例子:如果一個(gè)Math.class類要加載到JVM中需要經(jīng)過的步驟:類裝載子系統(tǒng)會(huì)把字節(jié)碼裝載到內(nèi)存區(qū)域啸澡,執(zhí)行引擎執(zhí)行程序
這里math.class的類信息就和靜態(tài)變量一起保存到了方法區(qū)當(dāng)中
ps2:String類型的字符串有兩種創(chuàng)建方式
第一種:String s1 =“abc”; 這種情況此時(shí)這個(gè)“abc”就是直接在這個(gè)方法區(qū)的常量池中袖订,如果下次還有相同的常量是“abc”的話,那么直接取這個(gè)值賦給它嗅虏,這種情況只會(huì)開辟一個(gè)內(nèi)存空間(即:方法區(qū))
第二種:String s2 = new String("abc") 此時(shí)會(huì)和普通創(chuàng)建對象一樣著角,開辟兩個(gè)內(nèi)存空間(即棧中一個(gè)用來保存句柄,堆中一個(gè)用來保存對象)
②:堆:創(chuàng)建的對象就放在這里旋恼,gc的主要場所
new 出來的對象都放這里
三:堆內(nèi)存中的GC機(jī)制是怎么運(yùn)作的
3.1 堆中的內(nèi)存分配
分為新生代和老年代
新生代中eden區(qū)吏口、survivor1區(qū)(也就是我們稱的From區(qū))、survivor2區(qū)(也就是我們稱的To區(qū))按照 8:1:1進(jìn)行分配
3.2 新生代運(yùn)作機(jī)制
new 出來的對象直接放入 eden區(qū)
當(dāng)eden區(qū)滿了之后會(huì)觸發(fā)一次minor GC冰更,存活的對象會(huì)放入survivor區(qū)1产徊,再下次minorGC后又存活的對象,會(huì)把survivor區(qū)1的存活數(shù)據(jù)復(fù)制到survivor區(qū)2蜀细,并清空survivor區(qū)1(復(fù)制算法)
3.3 老年代運(yùn)作機(jī)制
①:大對象直接進(jìn)入老年代舟铜,這里的大對象指的是字符串、數(shù)據(jù)這種在內(nèi)存中連續(xù)的對象
②:長期存活的對象將進(jìn)入老年代奠衔,minor gc后存活的對象有個(gè)計(jì)數(shù)器age +1谆刨,每熬過一次minor GC ,age都會(huì)+1塘娶,age= 15的時(shí)候,此時(shí)對象直接進(jìn)入老年代
③:minorGC后survivor區(qū)放不下痊夭,那么一部分也會(huì)被放入老年代
3.4 GC觸發(fā)條件
Minor GC觸發(fā)條件:Eden區(qū)滿時(shí)
Full GC觸發(fā)條件:
(1)調(diào)用System.gc時(shí)刁岸,系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行
(2)老年代空間不足
(3)方法去空間不足
(4)通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存
(5)由Eden區(qū)她我、From Space區(qū)向To Space區(qū)復(fù)制時(shí)虹曙,對象大小大于To Space可用內(nèi)存,則把該對象轉(zhuǎn)存到老年代番舆,且老年代的可用內(nèi)存小于該對象大小酝碳。
3.5 JVM如果判斷對象是否存活
①:引用-計(jì)數(shù)法:對象被引用時(shí),計(jì)數(shù)器+1恨狈,斷開時(shí)-1疏哗,為0時(shí)表示可以回收,但是存在循環(huán)引用問題禾怠,即A引用B返奉,B有引用了A,此時(shí)計(jì)數(shù)器不會(huì)為0刃宵,也就回收不了
②:可達(dá)性分析法
3.6 JVM垃圾回收算法
①:標(biāo)記-清除算法:標(biāo)記可回收垃圾衡瓶,統(tǒng)一回收,缺點(diǎn)是產(chǎn)生大量碎片
②:標(biāo)記-整理算法:同標(biāo)記-清除算法一個(gè)原理牲证,只是會(huì)對碎片進(jìn)行整理哮针,缺點(diǎn)是效率低(整理碎片需要時(shí)間)
③:復(fù)制算法:把內(nèi)存分為相同的兩個(gè)區(qū)域,每次只用一塊坦袍,一塊用完了再把存活的對象復(fù)制到另一塊十厢,清空之前一塊,缺點(diǎn)是不適合大量內(nèi)存復(fù)制使用捂齐,新生代minorGC中兩個(gè)survivor區(qū)就是用的該算法
④:分代收集算法:
新生代:復(fù)制算法
老年代:標(biāo)記清除蛮放、標(biāo)記整理算法