內(nèi)存區(qū)域
程序計數(shù)器、虛擬機棧、本地方法棧這三個是線程私有的;堆、方法區(qū)是線程公有的;
程序計數(shù)器:記錄線程走到字節(jié)碼的哪一行;
虛擬機棧:由棧幀組成,每個棧幀包含局部變量表、操作數(shù)棧、動態(tài)鏈接、方法返回地址,當(dāng)執(zhí)行到一個方法的時候,就會把這個方法以棧幀形式壓入棧
本地方法棧:與虛擬機棧差不多,只不過這個棧是給本地方法用的
堆:堆的垃圾回收算法常用的是分代回收法,所以堆被劃分出新生代,老年代;
方法區(qū): 1.7之前方法區(qū)的實現(xiàn)是永久代,會存儲已被虛擬機加載的 類信息、字段信息、方法信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼緩存等數(shù)據(jù)。****1.8之后方法區(qū)的實現(xiàn)變成了元空間,字符串常量池和靜態(tài)變量等移出到堆內(nèi)存中,其余的(主要是類型信息)被移到了元空間中。
元空間和永久代的區(qū)別就在于永久代會受JVM的總空間大小的限制,而元空間受限制的是內(nèi)存的總大小。
常量池:常量池中主要存放兩類數(shù)據(jù),一是字面量、二是符號引用。
字面量:比如String類型的字符串值或者定義為final類型的常量的值。
符號引用:
1.類或接口的全限定名(包括他的父類和所實現(xiàn)的接口)
2.變量或方法的名稱
3.變量或方法的描述信息
4.this
當(dāng)類的字節(jié)碼被加載到內(nèi)存中后,他的常量池信息就會集中放入到一塊內(nèi)存,這塊內(nèi)存就稱為運行時常量池,并且把里面的符號地址變?yōu)檎鎸嵉刂贰?/strong>
垃圾回收
判斷對象是否能夠回收有兩個辦法:引用計數(shù)法和可達性分析
垃圾收集的算法:標(biāo)記-清除、標(biāo)記-整理、標(biāo)記-復(fù)制、分代回收法
分代回收法
在內(nèi)存中,分為新生代,老年代,永久代;這里的永久代也有叫方法區(qū)。新生代又分為Eden區(qū),S0區(qū),和S1區(qū)。一個對象創(chuàng)建,存儲在Eden區(qū),當(dāng)Eden區(qū)滿了,就會觸發(fā)Minor GC,存活的對象將進入S0區(qū),S0區(qū)滿了之后會觸發(fā)Minor GC,清空S0區(qū)內(nèi)存,將存活的對象復(fù)制到S1區(qū);S1滿了也是GC清空到S0。倒來倒去,當(dāng)次數(shù)達到16(可改)次時,會進入老年代;老年代滿了會觸發(fā)Full GC(會stop the world)。再滿就會OOM了。
Full GC用的一般是標(biāo)記整理和標(biāo)記清除算法,所以不會轉(zhuǎn)移,而Minor GC一般用的是標(biāo)記-復(fù)制算法,所以會轉(zhuǎn)移來轉(zhuǎn)移去,同理,如果對象太大,會直接進老年代。
類加載過程
- 加載:
- 通過全類名獲取定義此類的二進制字節(jié)流
- 將字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)
- 在內(nèi)存中生成一個代表該類的
Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口
- 驗證:
驗證文件格式、元數(shù)據(jù)、符號引用、字節(jié)碼
- 準(zhǔn)備:
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,會給類變量一個默認值,不對成員變量做內(nèi)存分配。
從概念上講,類變量所使用的內(nèi)存都應(yīng)當(dāng)在方法區(qū)中進行分配。不過有一點需要注意的是:JDK 7 之前,HotSpot 使用永久代來實現(xiàn)方法區(qū)的時候,實現(xiàn)是完全符合這種邏輯概念的。 而在 JDK 7 及之后,HotSpot 已經(jīng)把原本放在永久代的字符串常量池、靜態(tài)變量等移動到堆中,這個時候類變量則會隨著 Class 對象一起存放在 Java 堆中。
- 解析:
解析階段是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程,也就是得到類或者字段、方法在內(nèi)存中的指針或者偏移量。
- 初始化:
- 給靜態(tài)變量賦值,給成員變量分配內(nèi)存,賦值
類加載器
JVM 中內(nèi)置了三個重要的 ClassLoader,除了 BootstrapClassLoader 其他類加載器均由 Java 實現(xiàn)且全部繼承自java.lang.ClassLoader:
-
BootstrapClassLoader(啟動類加載器) :最頂層的加載類,由 C++實現(xiàn),負責(zé)加載
%JAVA_HOME%/lib目錄下的 jar 包和類或者被-Xbootclasspath參數(shù)指定的路徑中的所有類。 -
ExtensionClassLoader(擴展類加載器) :主要負責(zé)加載
%JRE_HOME%/lib/ext目錄下的 jar 包和類,或被java.ext.dirs系統(tǒng)變量所指定的路徑下的 jar 包。 - AppClassLoader(應(yīng)用程序類加載器) :面向我們用戶的加載器,負責(zé)加載當(dāng)前應(yīng)用 classpath 下的所有 jar 包和類。
雙親委派機制: 自底向上檢查類是否被上層加載器加載,再從最頂向下嘗試加載類
雙親委派機制的好處:
- 避免類的重復(fù)加載
- 保護Java核心API不被篡改