JVM-概述和內存區(qū)域
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達
? 作者?|??亥碼
來源 |? urlify.cn/Vjiyqa
JVM的優(yōu)勢
Java的跨平臺性
一次編譯,到處運行

JVM跨語言

舉個例子
將groovy編譯之后的class文件用jvm運行
1、先配置好groovy環(huán)境
2、新建HelloWorld.groovy
class?HelloWorld?{
???static?main(args)?{
??????println?"hello?groovy...";
???}
}3、將其編譯成class文件
groovyc?HelloWorld.groovy
4、用java命令運行groovy編譯出來的HelloWorld.class文件
(注:全局搜索groovy-all-xxxx.jar的jar包,將其路徑作為classpath后的參數)
java?-classpath?"E:\codingEnvironment\IntelliJ?IDEA?2019.1.3\lib\groovy-all-2.4.15.jar;."?HelloWorldJVM整體結構
HotSpot VM

方法區(qū)和堆區(qū)是所有線程共享的內存區(qū)域;
Java棧又叫做jvm虛擬機棧。
執(zhí)行引擎等同于翻譯class文件的語言翻譯器。
方法區(qū)(永久代)在jdk8中又叫做元空間
Metaspace
方法區(qū)用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器(JIT編譯器,英文寫作Just-In-Time Compiler)編譯后的代碼等數據。
雖然Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區(qū)分開來。
運行時數據區(qū)
概述
堆內存:保存所有引用數據的真實信息;
棧內存:基本類型、運算、指向堆內存的指針;
方法區(qū):所以定義的方法的信息都保存方法區(qū)中,屬于共享區(qū);
程序計數器:是一個非常小的內存空間,用來保證程序依次執(zhí)行;
本地方法棧:每一次執(zhí)行遞歸方法的時候,都會將上一個方法入棧;
方法區(qū)(Method Area)
1. 什么是方法區(qū)(Method Area)?
方法區(qū)(Method Area)與Java堆一樣,是各個線程共享的內存區(qū)域。
2.方法區(qū)(Method Area)存儲什么?
它存儲已被Java虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等
域信息(成員變量)和方法信息可以看成在類型信息內

2.1 類信息
對每個加載的類型(類class、接口interface、枚舉enum、注解annotation),JVM必須在方法區(qū)中存儲以下類型信息:
這個類型的完整有效名稱(全名=包名.類名)
這個類型直接父類的完整有效名稱(?
java.lang.Object除外,其他類型若沒有聲明父類,默認父類是Object)這個類型的修飾符(
public、abstract、final的某個子集)這個類型直接接口的一個有序列表
除此之外還方法區(qū)(Method Area)存儲類信息還有類型的常量池( constant pool)
域(Field)信息
方法(Method)信息
除了常量外的所有靜態(tài)(static)變量
方法區(qū)(Method Area)存儲類信息請參考:參考博客
2.2 常量
static final修飾的成員變量都存儲于 方法區(qū)(Method Area)中
2.3 靜態(tài)變量
靜態(tài)變量又稱為類變量,類中被static修飾的成員變量都是靜態(tài)變量(類變量)
靜態(tài)變量之所以又稱為類變量,是因為靜態(tài)變量和類關聯在一起,隨著類的加載而存在于方法區(qū)(而不是堆中)
八種基本數據類型(byte、short、int、long、float、double、char、boolean)的靜態(tài)變量會在方法區(qū)開辟空間,并將對應的值存儲在方法方法區(qū),對于引用類型的靜態(tài)變量如果未用
new關鍵字為引用類型的靜態(tài)變量分配對象(如:static Object obj;)那么對象的引用obj會存儲在方法區(qū)中,并為其指定默認值null;若,對于引用類型的靜態(tài)變量如果用new關鍵字為引用類型的靜態(tài)變量分配對象(如:static Person person = new Person();),那么對象的引用person 會存儲在方法區(qū)中,并且該對象在堆中的地址也會存儲在方法區(qū)中(注意此時靜態(tài)變量只存儲了對象的堆地址,而對象本身仍在堆內存中);這個過程還涉及到靜態(tài)變量初始化問題,可以參考博客:靜態(tài)變量初始化相關
2.4 方法(Method)
程序運行時會加載類編譯生成的字節(jié)碼,這個過程中靜態(tài)變量(類變量)和靜態(tài)方法及普通方法對應的字節(jié)碼加載到方法區(qū)。
但是!!!方法區(qū)中沒有實例變量,這是因為,類加載先于對應類對象的產生,而實例變量是和對象關聯在一起的,沒有對象就不存在實例變量,類加載時沒有對象,所以方法區(qū)中沒有實例變量
靜態(tài)變量(類變量)和靜態(tài)方法及普通方法在方法區(qū)(Method Area)存儲方式是有區(qū)別的
棧(Stack)
棧(Stack):線程私有的內存區(qū)域
每個方法(Method)執(zhí)行時,都會創(chuàng)建一個棧幀,用于存儲局部變量表、操作數棧、動態(tài)鏈接、方法出口信息等
棧中所存儲的變量和引用都是局部的(即:定義在方法體中的變量或者引用),局部變量和引用都在棧中(包括final的局部變量)
八種基本數據類型(byte、short、int、long、float、double、char、boolean)的局部變量(定義在方法體中的基本數據類型的變量)在棧中存儲的是它們對應的值
棧中還存儲局部的對象的引用(定義在方法體中的引用類型的變量),對象的引用并不是對象本身,而是對象在堆中的地址,換句話說,局部的對象的引用所指對象在堆中的地址在存儲在了棧中。當然,如果對象的引用沒有指向具體的對象,對象的引用則是
null
Java堆(Java Heap)
Java堆(Java Heap) :被所有線程共享的一塊內存區(qū)域,在虛擬機啟動時創(chuàng)建。Java堆(Java Heap)唯一目的就是存放對象實例。所有的對象實例及數組都要在Java堆(Java Heap)上分配內存空間。
由關鍵字new產生的所有對象都存儲于Java堆(Java Heap)
!!!?實例變量(非static修飾的成員變量)和對象關聯在一起,所以實例變量也在堆中
java數組也在堆中開辟內存空間
棧、堆和方法區(qū)的關系

Java代碼大致執(zhí)行流程

java源程序--編譯javac-->字節(jié)碼文件.class-->類裝載子系統(tǒng)生成反射類(存入方法區(qū))--->運行時數據區(qū)(五大塊兒)--->執(zhí)行引擎-->解釋執(zhí)行+編譯執(zhí)行(JIT)-->操作系統(tǒng)(Win,Linux,Mac JVM)
作用
將高級語言轉化為機器能聽得懂的機器指令

Hotspot中方法區(qū)的變動
關于方法區(qū)的結構,在過去的版本jdk1.6/1.7/1.8當中均有變動,故在此提前聲明:
jdk1.6及之前:有永久代(permanent generation) ,靜態(tài)變量、字符串常量池存放在 永久代上。
jdk1.7:有永久代,但已經逐步“去永久代”,字符串常量池、靜態(tài)變量移除,保存在堆中。注意:
jdk1.8及之后:無永久代,類型信息、字段、方法、常量保存在本地內存的元空間,但字符串常量池、靜態(tài)變量仍留在堆空間.
JDK6

JDK7

注意:
jdk1.8及之后:無永久代,類型信息、字段、方法、常量保存在本地內存的元空間。
但字符串常量池、靜態(tài)變量仍留在堆空間。
除此之外,元空間(或稱方法區(qū)),不再使用虛擬機內存,而是使用本地內存。
JDK8

粉絲福利:108本java從入門到大神精選電子書領取
???
?長按上方鋒哥微信二維碼?2 秒 備注「1234」即可獲取資料以及 可以進入java1234官方微信群
感謝點贊支持下哈?

