1. 程式人生 > >JVM-概述和記憶體區域

JVM-概述和記憶體區域

[TOC] ## JVM的優勢 ### Java的跨平臺性 `一次編譯,到處執行` ![](http://img.linzworld.cn/img/20200906205143.png) ### JVM跨語言 ![](http://img.linzworld.cn/img/20200906205246.png) #### 舉個例子 將groovy編譯之後的class檔案用jvm執行 1. 先配置好groovy環境 ![](http://img.linzworld.cn/img/20200917111745.png) 2. 新建HelloWorld.groovy ```groovy class HelloWorld { static main(args) { println "hello groovy..."; } } ``` 3. 將其編譯成class檔案 ```powershell groovyc HelloWorld.groovy ``` ![](http://img.linzworld.cn/img/20200917111850.png) 4. 用java命令執行groovy編譯出來的HelloWorld.class檔案 (注:全域性搜尋groovy-all-xxxx.jar的jar包,將其路徑作為classpath後的引數) ```powershell java -classpath "E:\codingEnvironment\IntelliJ IDEA 2019.1.3\lib\groovy-all-2.4.15.jar;." HelloWorld ``` ![](http://img.linzworld.cn/img/20200917111917.png) ## JVM整體結構 HotSpot VM ![](http://img.linzworld.cn/img/20200906211123.png) 1. 方法區和堆區是所有執行緒共享的記憶體區域; 2. Java棧又叫做jvm虛擬機器棧。 3. 執行引擎等同於翻譯class檔案的語言翻譯器。 4. 方法區(永久代)在jdk8中又叫做元空間 Metaspace - 方法區用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器(JIT編譯器,英文寫作Just-In-Time Compiler)編譯後的程式碼等資料。 - 雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。 ### 執行時資料區 **概述** **堆記憶體**:儲存所有引用資料的真實資訊; **棧記憶體:**基本型別、運算、指向堆記憶體的指標; **方法區:**所以定義的方法的資訊都儲存方法區中,屬於共享區; **程式計數器:**是一個非常小的記憶體空間,用來保證程式依次執行; **本地方法棧:**每一次執行遞迴方法的時候,都會將上一個方法入棧; ### 方法區(Method Area) #### 1. 什麼是方法區(Method Area)? > **方法區(Method Area)與Java堆一樣,是各個執行緒共享**的記憶體區域。 #### 2.方法區(Method Area)儲存什麼? > **它儲存已被Java虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等** > > 域資訊(成員變數)和方法資訊可以看成在型別資訊內 ![](http://img.linzworld.cn/img/20200913235731.png) ##### 2.1 類資訊 **對每個載入的型別(類class、介面interface、列舉enum、註解annotation),JVM必須在方法區中儲存以下型別資訊:** - 這個型別的**完整有效名稱(全名=包名.類名)** - 這個型別**直接父類**的完整有效名稱( `java.lang.Object`除外,其他型別若沒有宣告父類,預設父類是Object) - 這個型別的修飾符(`public、abstract、final`的某個子集) - 這個型別**直接介面**的一個**有序列表** **除此之外還方法區(Method Area)儲存類資訊還有** - 型別的常量池( constant pool) - 域(Field)資訊 - 方法(Method)資訊 - 除了常量外的所有靜態(static)變數 方法區(Method Area)儲存類資訊請參考:[參考部落格](http://blog.csdn.net/zzhangxiaoyun/article/details/7518917) ##### 2.2 常量 - **static final修飾的成員變數**都儲存於 方法區(Method Area)中 ##### 2.3 靜態變數 - **靜態變數又稱為類變數,類中被static修飾的成員變數都是靜態變數(類變數)** - **靜態變數之所以又稱為類變數,是因為靜態變數和類關聯在一起,隨著類的載入而存在於方法區(而不是堆中)** - 八種基本資料型別(byte、short、int、long、float、double、char、boolean)的靜態變數**會在方法區開闢空間,並將對應的值儲存在方法方法區**,對於**引用型別的靜態變數**如果未用`new`關鍵字為**引用型別的靜態變數**分配物件(如:`static Object obj;`)那麼**物件的引用obj**會儲存在方法區中,併為其指定預設值`null`;若,對於**引用型別的靜態變數**如果用`new`關鍵字為**引用型別的靜態變數**分配物件(如:`static Person person = new Person();`),那麼**物件的引用person 會儲存在方法區中,並且該物件在堆中的地址**也會儲存在方法區中(**注意此時靜態變數只儲存了物件的堆地址,而物件本身仍在堆記憶體中**);這個過程還涉及到靜態變數初始化問題,可以參考部落格:[靜態變數初始化相關](http://blog.csdn.net/u013241673/article/details/78221857) ##### 2.4 方法(Method) - 程式執行時會載入**類編譯生成的位元組碼**,這個過程中**靜態變數(類變數)和靜態方法**及**普通方法**對應的位元組碼載入到方法區。 - 但是!!!方法區中**沒有例項變數,這是因為,類載入先於對應類物件的產生,而例項變數是和物件關聯在一起的,沒有物件就不存在例項變數,類載入時沒有物件,所以方法區中沒有例項變數** - **靜態變數(類變數)和靜態方法**及**普通方法**在方法區(Method Area)儲存方式是有區別的 ### 棧(Stack) > 棧(Stack):執行緒私有的記憶體區域 - 每個**方法(Method)執行時,都會建立一個棧幀,用於儲存區域性變量表、運算元棧、動態連結、方法出口資訊等** - 棧中所儲存的**變數和引用**都是**區域性的(即:定義在方法體中的變數或者引用),區域性變數和引用都在棧中(包括final的區域性變數)** - 八種基本資料型別(byte、short、int、long、float、double、char、boolean)的**區域性變數(定義在方法體中的基本資料型別的變數)**在棧中儲存的是它們對應的值 - 棧中還儲存**區域性的物件的引用(定義在方法體中的引用型別的變數)**,**物件的引用**並不是物件本身,而是物件在**堆中的地址**,換句話說,**區域性的物件的引用**所指物件在**堆中的地址**在儲存在了棧中。當然,如果物件的引用沒有指向具體的物件,**物件的引用**則是`null` ### Java堆(Java Heap) > Java堆(Java Heap) :被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。Java堆(Java Heap)唯一目的就是存放物件例項。**所有的物件例項及陣列**都要在**Java堆(Java Heap)**上分配記憶體空間。 - 由**關鍵字new產生的所有物件**都儲存於**Java堆(Java Heap)** - !!! **例項變數(非static修飾的成員變數)**和物件關聯在一起,所以例項變數也在堆中 - **java陣列也在堆中開闢記憶體空間** ### 棧、堆和方法區的關係 ![](http://img.linzworld.cn/img/20200917141742.png) ### Java程式碼大致執行流程 ![](http://img.linzworld.cn/img/20200906211713.png) java源程式--編譯javac-->位元組碼檔案.class-->類裝載子系統生成反射類(存入方法區)--->執行時資料區(五大塊兒)--->執行引擎-->解釋執行+編譯執行(JIT)-->作業系統(Win,Linux,Mac JVM) #### 作用 將高階語言轉化為機器能聽得懂的機器指令 ![](http://img.linzworld.cn/img/20200906211932.png) ## Hotspot中方法區的變動 關於方法區的結構,在過去的版本jdk1.6/1.7/1.8當中均有變動,故在此提前宣告: - jdk1.6及之前:有永久代(permanent generation) ,靜態變數、字串常量池存放在 永久代上。 - jdk1.7:有永久代,但已經逐步“去永久代”,字串常量池、靜態變數移除,儲存在堆中。注意: - jdk1.8及之後: 無永久代,型別資訊、欄位、方法、常量儲存在本地記憶體的元空間,但字串常量池、靜態變數仍留在堆空間. ### JDK6 ![img](https://img2020.cnblogs.com/blog/1846149/202008/1846149-20200809213838042-161042513.png) ### JDK7 ![img](https://img2020.cnblogs.com/blog/1846149/202008/1846149-20200809213856394-1788531515.png) 注意: jdk1.8及之後: 無永久代,型別資訊、欄位、方法、常量儲存在本地記憶體的元空間。 但字串常量池、靜態變數仍留在堆空間。 除此之外,元空間(或稱方法區),不再使用虛擬機器記憶體,而是使用本地記憶體。 ### JDK8 ![img](https://img2020.cnblogs.com/blog/1846149/202008/1846149-20200809213935140-298002178.png) ## 參考資料 [JVM_01 簡介 - 傲嬌的大王 - 部落格園](https://www.cnblogs.com/yanl55555/p/12610952.html) [(3條訊息)JVM學習筆記(三)------記憶體管理和垃圾回收_走向架構師之路-CSDN部落格](https://blog.csdn.net/cutesource/article/details/5906705?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase) [(3條訊息)Java虛擬機器(JVM)面試題(2020最新版)_ThinkWon的部落格-CSDN部落格](https://blog.csdn.net/ThinkWon/article/details/104390752?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase) [(4條訊息)Java方法區、棧及堆_蝸牛-CSDN部落格](https://blog.csdn.net/u013241673/article/details/78574770?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase) [Jvm垃圾回收器(終結篇) - 不二塵 - 部落格園](https://www.cnblogs.com/chenpt/p/9803298.html) [24個Jvm面試題總結及答案_ITPUB部落格](http://blog.itpub.net/69917606/viewspace-26