內(nèi)存區(qū)域
程序計(jì)數(shù)器、虛擬機(jī)棧救巷、本地方法棧這三個(gè)是線程私有的盹廷;堆、方法區(qū)是線程公有的管怠;
程序計(jì)數(shù)器:記錄線程走到字節(jié)碼的哪一行渤弛;
虛擬機(jī)棧:由棧幀組成甚带,每個(gè)棧幀包含局部變量表鹰贵、操作數(shù)棧、動(dòng)態(tài)鏈接碉输、方法返回地址,當(dāng)執(zhí)行到一個(gè)方法的時(shí)候肄梨,就會(huì)把這個(gè)方法以棧幀形式壓入棧
本地方法棧:與虛擬機(jī)棧差不多众羡,只不過(guò)這個(gè)棧是給本地方法用的
堆:堆的垃圾回收算法常用的是分代回收法粱侣,所以堆被劃分出新生代甜害,老年代球昨;
方法區(qū): 1.7之前方法區(qū)的實(shí)現(xiàn)是永久代主慰,會(huì)存儲(chǔ)已被虛擬機(jī)加載的 類信息、字段信息该肴、方法信息藐不、常量雏蛮、靜態(tài)變量挑秉、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)犀概。****1.8之后方法區(qū)的實(shí)現(xiàn)變成了元空間立哑,字符串常量池和靜態(tài)變量等移出到堆內(nèi)存中,其余的(主要是類型信息)被移到了元空間中姻灶。
元空間和永久代的區(qū)別就在于永久代會(huì)受JVM的總空間大小的限制铛绰,而元空間受限制的是內(nèi)存的總大小。
常量池:常量池中主要存放兩類數(shù)據(jù)产喉,一是字面量至耻、二是符號(hào)引用若皱。
字面量:比如String類型的字符串值或者定義為final類型的常量的值镊叁。
符號(hào)引用:
1.類或接口的全限定名(包括他的父類和所實(shí)現(xiàn)的接口)
2.變量或方法的名稱
3.變量或方法的描述信息
4.this
當(dāng)類的字節(jié)碼被加載到內(nèi)存中后尘颓,他的常量池信息就會(huì)集中放入到一塊內(nèi)存,這塊內(nèi)存就稱為運(yùn)行時(shí)常量池晦譬,并且把里面的符號(hào)地址變?yōu)檎鎸?shí)地址疤苹。
垃圾回收
判斷對(duì)象是否能夠回收有兩個(gè)辦法:引用計(jì)數(shù)法和可達(dá)性分析
垃圾收集的算法:標(biāo)記-清除敛腌、標(biāo)記-整理尤莺、標(biāo)記-復(fù)制、分代回收法
分代回收法
在內(nèi)存中,分為新生代缔杉,老年代,永久代;這里的永久代也有叫方法區(qū)拣宏。新生代又分為Eden區(qū),S0區(qū)学歧,和S1區(qū)。一個(gè)對(duì)象創(chuàng)建,存儲(chǔ)在Eden區(qū)洒缀,當(dāng)Eden區(qū)滿了,就會(huì)觸發(fā)Minor GC饺饭,存活的對(duì)象將進(jìn)入S0區(qū)军援,S0區(qū)滿了之后會(huì)觸發(fā)Minor GC胸哥,清空S0區(qū)內(nèi)存银酬,將存活的對(duì)象復(fù)制到S1區(qū);S1滿了也是GC清空到S0宠哄。倒來(lái)倒去,當(dāng)次數(shù)達(dá)到16(可改)次時(shí)承粤,會(huì)進(jìn)入老年代;老年代滿了會(huì)觸發(fā)Full GC(會(huì)stop the world)缰盏。再滿就會(huì)OOM了透揣。
Full GC用的一般是標(biāo)記整理和標(biāo)記清除算法侍咱,所以不會(huì)轉(zhuǎn)移,而Minor GC一般用的是標(biāo)記-復(fù)制算法,所以會(huì)轉(zhuǎn)移來(lái)轉(zhuǎn)移去木柬,同理怜森,如果對(duì)象太大,會(huì)直接進(jìn)老年代伶授。
類加載過(guò)程
- 加載:
- 通過(guò)全類名獲取定義此類的二進(jìn)制字節(jié)流
- 將字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
- 在內(nèi)存中生成一個(gè)代表該類的
Class
對(duì)象疮蹦,作為方法區(qū)這些數(shù)據(jù)的訪問(wèn)入口
- 驗(yàn)證:
驗(yàn)證文件格式、元數(shù)據(jù)绅项、符號(hào)引用、字節(jié)碼
- 準(zhǔn)備:
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,會(huì)給類變量一個(gè)默認(rèn)值妥色,不對(duì)成員變量做內(nèi)存分配搪花。
從概念上講,類變量所使用的內(nèi)存都應(yīng)當(dāng)在方法區(qū)中進(jìn)行分配垛膝。不過(guò)有一點(diǎn)需要注意的是:JDK 7 之前鳍侣,HotSpot 使用永久代來(lái)實(shí)現(xiàn)方法區(qū)的時(shí)候,實(shí)現(xiàn)是完全符合這種邏輯概念的倚聚。 而在 JDK 7 及之后,HotSpot 已經(jīng)把原本放在永久代的字符串常量池敛助、靜態(tài)變量等移動(dòng)到堆中,這個(gè)時(shí)候類變量則會(huì)隨著 Class 對(duì)象一起存放在 Java 堆中。
- 解析:
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程粘招,也就是得到類或者字段邓线、方法在內(nèi)存中的指針或者偏移量淌友。
- 初始化:
- 給靜態(tài)變量賦值,給成員變量分配內(nèi)存骇陈,賦值
類加載器
JVM 中內(nèi)置了三個(gè)重要的 ClassLoader震庭,除了 BootstrapClassLoader 其他類加載器均由 Java 實(shí)現(xiàn)且全部繼承自java.lang.ClassLoader
:
-
BootstrapClassLoader(啟動(dòng)類加載器) :最頂層的加載類,由 C++實(shí)現(xiàn)你雌,負(fù)責(zé)加載
%JAVA_HOME%/lib
目錄下的 jar 包和類或者被-Xbootclasspath
參數(shù)指定的路徑中的所有類器联。 -
ExtensionClassLoader(擴(kuò)展類加載器) :主要負(fù)責(zé)加載
%JRE_HOME%/lib/ext
目錄下的 jar 包和類,或被java.ext.dirs
系統(tǒng)變量所指定的路徑下的 jar 包婿崭。 - AppClassLoader(應(yīng)用程序類加載器) :面向我們用戶的加載器拨拓,負(fù)責(zé)加載當(dāng)前應(yīng)用 classpath 下的所有 jar 包和類。
雙親委派機(jī)制: 自底向上檢查類是否被上層加載器加載氓栈,再?gòu)淖铐斚蛳聡L試加載類
雙親委派機(jī)制的好處:
- 避免類的重復(fù)加載
- 保護(hù)Java核心API不被篡改