JVM篇1:[-結構綜述-]

Java虛擬機 (JVM--Java Virtual Machine)html

前言

對java虛擬機的介紹文章多如牛毛,寫本文目的在於梳理一下,也方便之後翻來看看。  
另外網上文章的圖都挺醜的,本文90%的圖都出於在下親筆,如圖有錯誤,請指出,定當當即更正  
本文主要介紹一下Java虛擬機的抽象結構以及一些基礎的概念
複製代碼

1、幾個概念簡介

1.JDK、JRE、JVM
有了JRE就能運行java程序,若是隻是運行軟件,裝個JRE就好了。
咱們通常說java8,java10都是指的JDK,是java開發者使用的工具集,是一個大的概念,下面是java8的JDK組成
複製代碼

java8.png


2.JDK、JRE、JVM的關係

JDK:Java 語言的軟件開發工具包(Java Development Kit)
JRE: Java運行時環境(Java Runtime Environment)
JVM: Java虛擬機(Java Virtual Machine)java

jdk-jre-jvm.png


3.歷史上的java虛擬機類型

虛擬機即:模擬計算機功能,並提供統一操做接口,從而實現代碼在不一樣平臺的一致性。
從本質上來看,JVM是一個抽象接口,它有不少實現(以下),而這些實現也只是應用程序而已。
Java發展至今JVM也有過更新迭代,也有基於不一樣場景下使用的JVM。算法

Sun Classic VM 第一款商用Java 虛擬機,純解釋器方式執行java代碼。(已退出歷史舞臺)
EXact VM 編譯器解釋器混合工做,很快被HotSpot VM取代(已退出歷史舞臺)
HotSpot VM 沿用至今
KVM 手機端----效率低(已退出歷史舞臺)
JRockit 專一服務端應用
J9 IBM公司
Microsoft JVM windows----平臺專用(已退出歷史舞臺)
Taobao VM 淘寶根據HotSpot VM定製
Dalvik 安卓虛擬機,寄存器架構,執行.dex文件(.class-->.dex)
複製代碼

4.Java虛擬機結構

虛擬機的內部體系結構


2、Java虛擬機結構簡述

1..class文件和類加載器
1-1. .class文件

若是對class感興趣,能夠詳見官方文檔,對class文件介紹的很是細緻,之後會寫個專篇,這裏不深刻。
java第一天便知道javac命令能將.java生成.class文件,而後就上手IDE,基本也就與class文件無緣了windows

class.png

編譯和執行.png


1-2.類加載器子系統

關於類加載器子系統這裏展現也不深刻,只要知道考它將java字節碼文件載入JVM便可
詳見:JVM篇2:[-加載器ClassLoader-]bash

java文件編譯和運行.png


2.運行時數據區
2-1. 程序計數器
當前線程私有,即每個線程都有一個,經過改變它來選取下一條須要執行的字節碼指令 
內存空間較小,JVM中惟一不會出現OutOfMemoryError狀況
若是該線程正在執行一個本地方法,那麼此時程序計數器的值是「undefined」
複製代碼

2-2. Java虛擬機棧
調節參數:-Xss = 
---->[1.棧幀(StatckFrame)]-------------------------------------------
|--- 一個線程的每一個方法在執行的同時,都會建立一個棧幀。  
|--- 棧幀中存儲的有局部變量表、操做站、動態連接、方法出口等。  
|--- 當方法被調用時,棧幀入棧,當方法執行完成時,棧幀出棧。

---->[2.其餘相關]-------------------------------------------
|--- 存取的速度快,僅次於寄存器
|--- 存儲着方法的相關局部變量,包括各類基本數據類型,對象的引用,返回地址等。  
|--- 局部變量表的內存空間在編譯器完成分配,運行期不能改變其大小

---->[3.異常相關]-------------------------------------------
棧溢出:    Java虛擬機會拋出StackOverflowError
內存溢出:  建立/動態擴展時沒有足夠的內存建立對應的Java虛擬機棧,拋出OutOfMemoryError異常
複製代碼

Java虛擬機棧中局部變量表.png

Java虛擬機棧中方法出入棧.png


2-3. Java虛擬機棧``本地方法棧
當前線程私有,本地方法棧支持Native方法調用
HotSpot VM將本地方法棧和Java虛擬機棧合二爲一
異常狀況:StackOverflowError和OutOfMemoryError
複製代碼

關於線程私有和線程間共享,詳見:Java內存模型(JMM--Java Memory Model)架構


2-4.方法區
-XX:PermSize = 
-XX:MaxPermSize = 
---->[1.基本介紹]-------------------------------------------
當前線程共享區域:用於存儲已經被虛擬機加載的[類信息](即加載類時須要加載的信息,
包括版本、field、方法、接口等信息)、final常量、靜態變量、編譯器即時編譯的代碼等。  

---->[2.運行時常量池]-------------------------------------------
|---用於存儲編譯期就生成的字面常量、符號引用、翻譯出來的直接引用  
|---存儲在運行時產生的常量(好比String類的intern方法,做用是String維護了一個常量池,若是調用的字符「abc」已經在常量池中,則返回池中的字符串地址,不然,新建一個常量加入池中,並返回地址)

[符號引用]:編碼是用字符串表示某個變量、接口的位置,直接引用就是根據符號引用翻譯出來的地址,將在類連接階段完成翻譯 

---->[3.異常相關]-------------------------------------------
異常狀況:OutOfMemoryError異常。 
複製代碼

方法區-運行時常量池.png


方法區、永久帶和元空間簡介併發

方法區(Method Area):jvm規範裏面的運行時數據區的一個組成部分(接口層面)
永久帶(Perm):jdk7及以前的版本含有,是方法區的具體實現。(實現層面)
元空間(Metaspace):jdk8及以後的版本含有,是方法區的具體實現。(實現層面) # 元空間使用本地內存,不在JVM中

其實理解起來也不難:先定義和使用接口,再用具體實現完成工做。
複製代碼

2-5.Java堆

Java堆的結構.png

Java 堆:存放對象
    |---新生代:存儲新生的對象
        |--- Eden(E區):存放JVM中剛生成的Java對象
        |--- Survivor(S區)
            |--- FromSpace (S0)
            |--- ToSpace (S1)
    |---老年代:存儲長期存活的對象
        |--- 年齡達標(新生代中GC下存活的次數),可經過 -XX:MaxTenuringThreshold 指定
        |--- 超大對象,直接進入老年代 。 

非堆:存儲程序運行時長期存活的對象,好比類的元數據、方法、常量、屬性等。
複製代碼

-XX:NewSize=        新生代大小
-XX:SurvivorRatio=  E區與兩個S區的比值 默認 8:2
-XX:NewRatio=       新生代和老年代的比值  
-XX:MaxTenuringThreshold 進入老年代年齡閥值

-Xms 初始堆大小 : 默認是物理內存的1/64
-Xmx 最大堆大小 : 默認是物理內存的1/4
-XX:PermSize= 非堆內存初始值: 默認是物理內存的1/64
-XX:MaxPermSize= 最大非堆內存: 默認是物理內存的1/4
堆大小:新生代 + 老年代 + 持久代
複製代碼

3、堆與垃圾回收機制

Minor GC : 清理新生代
Full GC  : 清理整個堆空間
複製代碼

1:MinorGC
通常新建立對象進入E區,當E區內存用完後,觸發MinorGC。
存活的對象最終進入SurvivorFrom
複製代碼


2.Survivor的兩個區域FromTo
1.當E區再度裝滿
2.觸發MinorGC回收
3.存活的對象(包括From中)複製存放入To
4.To和From調換名稱
複製代碼


3.幾個小問題:
[1].爲何要分新生代和老年代?
|--- 對象的生存情況不一樣,使用不一樣的回收算法,優化GC性能
|--- 在新生代對象可能被頻繁建立或銷燬(朝生夕死),老年代對象回收較少

[2].Survivor區存在的意義? 
提升對象進入老年代的門檻,減小FullGC 的次數(FullGC很耗時)

[3].S0和S1有什麼做用?  
避免Survivor區空間的碎片化
複製代碼

4、垃圾回收算法

垃圾對象的斷定
    |---引用計數法
    |---可達性分析
回收算法
    |---標記清除
    |---複製
    |---標記整理
    |---分代收集
垃圾回收器:
    |---Serial
    |---Parnew
    |---CMS
    |---G1
複製代碼

1.垃圾對象的斷定
1-1.引用計數法
在對象中添加引用計數器,當該對象被引用時,引用計數器+1,引用失效時,計數器-1
對象循環引用會失效
複製代碼

1-1.可達性分析

Java中GC Root包括:oracle

[1].虛擬機棧中的引用的對象。
[2].方法區中的類靜態屬性引用的對象。
[3].方法區中的常量引用的對象。
[4].本地方法棧(jni)即通常說的Native的引用對象。
複製代碼

一個對象和GC Root之間沒有連接,那麼該對象可回收
好比ObjC和ObjB之間的鏈接斷開,橙色區域的對象可回收jvm


2.回收算法
2-1: 標記-清除(Mark-Sweep)

---->[方式]----------------------------------
[1].標記出全部須要存活的對象
[2].標記完成以後統一回收掉未被標記的對象。

---->[缺點]----------------------------------
[1].標記和清除效率都不高。
[2].會產生大量的不連續的內存碎片。
大量空間碎片的缺點:當程序須要爲較大對象分配內存時,沒法找到足夠的連續內存而出發GC。
複製代碼

2-2:標記-整理(Mark-Compact)

---->[方式]----------------------------------
[1].標記出全部存活的對象
[2].讓全部存活的對象都向一端移動,在移動過程當中清理掉未標記的對象

---->[優劣]----------------------------------
優:不會產生大量不連續內存碎片問題
劣:要執行較多的複製操做,效率將會變低,不適合存活率高的狀況
複製代碼

2-3: 複製算法(Copy)

---->[方式]----------------------------------
[1].將可用內存按容量分紅大小相等的兩塊,每次只使用其中一塊。
[2].回收時,將內存中存活的對象複製到另外一塊內存,而後清理掉該內存空間

---->[優劣]----------------------------------
優:無空間碎片,實現簡單,運行高效
劣:可以使用的內存降爲原來一半
複製代碼

2-4:分代收集

這不是什麼算法,而是根據不一樣的代來使用什麼時候的算法工具

新生代:可回收對象較多,回收率大。
    |--- 複製算法,高效,無碎片,從E區到S區。
老年代:可回收對象少,回收率低。
    |--- 標記-整理算法,無碎片。
複製代碼

3.垃圾回收器簡介
---->[新生代回收器:minor GC]----------------------------
[1].Serial(串行GC)-複製
[2].ParNew(並行GC)-複製
[3].Parallel Scavenge(並行回收GC)-複製

---->[老年代回收器:full GC]----------------------------
[4].Serial Old(MSC)(串行GC)-標記-整理
[5].CMS(併發GC)-標記-清除
[6].Parallel Old(並行GC)--標記-整理

---->[G1獨立完成]-------------------------------
[7].G1(JDK1.7+)
複製代碼

好了,綜述就到這裏,具體詳情可見接下來的各篇專題。

相關文章
相關標籤/搜索