JVM之JVM的體繫結構

来源:https://www.cnblogs.com/jalja365/archive/2020/01/14/12184872.html
-Advertisement-
Play Games

棧中的數據都是以棧幀(Stack Frame)的格式存在,棧幀是一個記憶體區塊,是一個數據集,是一個有關方法( Method )和運行期數據的數據集,當一個方法A被調用時就產生了一個棧幀 Fl ,並被壓入到棧中, A方法又調用了B方法,於是產生棧幀 F2 也被壓入棧,B方法又調用了C方法,於是產生棧幀... ...


一、JDK的組成

JDK:JDK是Java開發工具包,是Sun Microsystems針對Java開發員的產品。JDK中包含JRE(在JDK的安裝目錄下有一個名為jre的目錄,裡面有兩個文件夾bin和lib,在這裡可以認為bin里的就是jvm,lib中則是jvm工作所需要的類庫,而jvm和 lib和起來就稱為jre)和一堆Java工具(javac/java/jdb等)和Java基礎的類庫(即Java API 包括rt.jar)。

Java Runtime Environment(JRE):是運行基於Java語言編寫的程式所不可缺少的運行環境。也是通過它,Java的開發者才得以將自己開發的程式發佈到用戶手中,讓用戶使用。JRE中包含了Java virtual machine(JVM),runtime class libraries和Java application launcher,這些是運行Java程式的必要組件。

JVM(java virtual machine):就是我們常說的java虛擬機,它是整個java實現跨平臺的最核心的部分,所有的java程式會首先被編譯為.class的類文件,這種類文件可以在虛擬機上執行。

二、JVM的位置

JVM就是運行在操作系統之上的一個軟體

 三、JVM體繫結構

JVM的組成:

  • 類載入子系統 Class loader
  • 運行時數據區 JVM 記憶體模型
  • 執行引擎

四、類載入子系統


 ======================類載入器=======================

 類載入器(ClassLoader):負責載入class文件(classs文件在文件開頭有特定的文件標識),將class文件位元組碼內容載入到記憶體中,並將這些內容轉換成方法區中的運行時數據結構;ClassLoader只負責載入class文件的載入,至於它是否可以運行,則由Execution Engine決定。

 

1、BootStrapLoader(引導類載入器):類載入器也是java類,他們也需要類載入器載入進入記憶體,顯然必須要有第一個不是java類的類載入器,來完成這個工作,這個正是BootStrap。負責載入存放在D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib下,或被-Xbootclasspath參數指定的路徑中的,並且能被虛擬機識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader載入);啟動類載入器是無法被Java程式直接引用的;rt.jar 裡面的類的載入器都是BootStrapLoader。

 2、Extension ClassLoader(擴展類載入器):該載入器由sun.misc.Launcher$ExtClassLoader實現,它負責載入D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib\ext目錄中,或者由java.ext.dirs系統變數指定的路徑中的所有類庫(如javax.*開頭的類),開發者可以直接使用擴展類載入器。ext 目錄下所有的類的載入器都是Extension ClassLoader

 

 3、Application ClassLoader(應用程式類載入器):該類載入器由sun.misc.Launcher$AppClassLoader來實現,它負責載入用戶類路徑(ClassPath)所指定的類,開發者可以直接使用該類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。

====================JVM類載入機制==============

全盤負責:當前線程的類載入器負責載入某個Class時,該Class所依賴的和引用的其他Class也將由該類載入器負責載入,除非顯示使用CLassLoader.loadClass()指定類載入器來載入

父類委托:先讓父類載入器試圖載入該類,只有在父類載入器無法載入該類時才嘗試從自己的類路徑中載入該類。所以我們在開發中儘量不要使用與JDK相同的類(例如自定義一個java.lang.System類),因為父類載入器中已經有一份java.lang.System類了,它會直接將該類給程式使用,而你自定義的類壓根就不會被載入。

雙親委派模型:

  雙親委派模型的工作流程是:如果一個類載入器收到了類載入的請求,它首先不會自己去嘗試載入這個類,而是把請求委托給父載入器去完成,依次向上,因此,所有的類載入請求最終都應該被傳遞到頂層的啟動類載入器中,
只有當父載入器在它的搜索範圍中沒有找到所需的類時,即無法完成該載入,子載入器才會嘗試自己去載入該類。
雙親委派機制:

  • 1、當AppClassLoader載入一個class時,它首先不會自己去嘗試載入這個類,而是把類載入請求委派給父類載入器ExtClassLoader去完成。
  • 2、當ExtClassLoader載入一個class時,它首先也不會自己去嘗試載入這個類,而是把類載入請求委派給BootStrap ClassLoader去完成。
  • 3、如果BootStrap ClassLoader載入失敗(例如在$JAVA_HOME/jre/lib里未查找到該class),會使用ExtClassLoader來嘗試載入;
  • 4、若ExtClassLoader也載入失敗,則會使用AppClassLoader來載入,如果AppClassLoader也載入失敗,則會報出異常ClassNotFoundException。

雙親委派模型意義:

  •   -系統類防止記憶體中出現多份同樣的位元組碼
  •   -保證Java程式安全穩定運行

 

 ==================類的載入過程======================

類的載入過程:JVM將javac編譯好的class位元組碼文件載入到記憶體中,並對該數據進行驗證、解析和初始化、形成JVM可以直接使用的JAVA類,最終回收(卸載)的過程。

位元組碼(.class)文件來源:

  • – 從本地系統中直接載入
  • – 通過網路下載.class文件
  • – 從zip,jar等歸檔文件中載入.class文件
  • – 從專有資料庫中提取.class文件
  • – 將Java源文件動態編譯為.class文件

1、載入:載入階段其實就是JVM通過一個類的全限定名來獲取其定義的二進位位元組流,並將這個位元組流所代表的靜態存儲結構轉化為方法區的運行時數據結構且在Java堆中生成一個代表這個類的java.lang.Class對象,作為對方法區中這些數據的訪問入口。在該階段我們開發人員可以干預,例如:我們可以指定類載入器來載入該位元組數組或者自定義類載入器來載入。

2、鏈接:將java類的二進位代碼合併到JVM的運行狀態中的過程

  • a、驗證:驗證是為了確保Class文件的位元組流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。
  • b、準備:該階段是在方法區中為類變數(static變數)分配記憶體並設置類變數初始值。例如:public static int flag=1;該階段初始化值為0。
  • c、解析:虛擬機將常量池中的符號引用替換為直接引用的過程。(直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄)

3、初始化:初始化為類的靜態變數賦予正確的初始值,JVM負責對類進行初始化,主要對類變數進行初始化。

  • 初始化階段就是執行類構造器<clinit>()的過程,類構造器<clinit>()是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊中的語句合併產生的。
  • 當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先初始化其父類。
  • 虛擬機會保證一個類的<clinit>()方法在多線程環境中被正確加鎖和同步。
  • 當訪問一個java 類的靜態域時,只有正真申明這個域的類才會被初始化。

4、使用:程式使用JVM載入的類

5、卸載 

  • 執行了System.exit()方法
  • JVM垃圾回收機制觸發回收
  • 程式正常執行結束
  • 程式在執行過程中遇到了異常或錯誤而異常終止
  • 由於操作系統出現錯誤而導致Java虛擬機進程終止

五、運行時數據區

1、方法區(Method Area):方法區是各個線程共用的記憶體區域;方法區用於存儲已被虛擬機載入的類的模板信息、常量、靜態變數等;雖然Java虛擬機規範把方法區描述為堆的一部分,但是他還有個別名叫做Non-heap(非堆),目的應該是與Java堆區分開來;根據Java虛擬機規範的規定,當方法區無法滿足記憶體分配需求時,將拋出OutOfMemoryError 異常;相對而言,垃圾收集在這個區域是比較少出現的,但並非數據進入了方法區就如永久代的名字一樣永久存在了。這區域的記憶體回收目標重要是針對常量池的回收和類型的卸載。
方法區只是一個規範:

  • 在HotSpot虛擬機上開發、部署程式我們把方法區稱為“永久代”(Permanent Generation);
  • 他虛擬機(如 BEA JRockit、IBM J9 等)來說是不存在永久代的概念的。
  • HotSpot虛擬機在JKD.8中已經沒有方法區的概念了,他使用元空間代替該區域

2、PC寄存器(程式計數器):每個線程都有一個程式計數器,是線程私有的;就是一個指針,指向方法區中的方法位元組碼(用來存儲指向下一條指令的地址,既將要執行的指令代碼),由執行引擎讀取下一條指令,是一個非常小的記憶體空間,幾乎可以忽略不記;它是當前線程所執行的位元組碼的行號指示器,位元組碼解釋器通過改變這個計數器的值來選取下一條需要執行的位元組碼指令。如果執行的是一個Native方法,那這個計數器是空的;用以完成分支、迴圈、跳轉、異常處理、線程恢復等基礎功能。不會發生記憶體溢出OOM錯誤
本地方法棧(Native Stack):與虛擬機棧基本類似,區別在於虛擬機棧為虛擬機執行的java方法服務,而本地方法棧則是為Native方法服務。(棧的空間大小遠遠小於堆)

3、虛擬機棧(Vm Stack)
  棧也叫棧記憶體,主管 Java 程式的運行,是線上程創建時創建,它的生命期是跟隨線程的生命期,線程結束棧記憶體也就仔放,對於棧來說不存在垃圾回收問題,只要線程結束該棧就釋放,生命周期和線程一致,是線程私有的。8種基木類型的變數+對象的引用變數+實例方法都是在函數的棧記憶體中分配。

棧的運行原理:棧中的數據都是以棧幀(Stack Frame)的格式存在,棧幀是一個記憶體區塊,是一個數據集,是一個有關方法( Method )和運行期數據的數據集,當一個方法A被調用時就產生了一個棧幀 Fl ,並被壓入到棧中, A方法又調用了B方法,於是產生棧幀 F2 也被壓入棧,B方法又調用了C方法,於是產生棧幀 F3 也被壓入棧,執行完畢後,先彈出 F3 棧幀,再彈出 F2 棧幀,再彈出 Fl 棧幀 以此類推, 遵循“先進後出” / “後進先出”原則。每個方法執行的同時都會創建一個棧幀,用於存儲局部變數表、操作數、動態鏈接、方法出口等信息,每一個方法從調用直至執行完畢的過,就對應著一個棧幀在虛擬機中入棧到出棧的過程。棧的大小和具體JVM的實現有關,通常在 256K~1024K 之間, 1M 左右。

JVM棧的特點:

  • 局部變數表所需的記憶體空間在編譯期間完成記憶體分配。當進入一個方法時,這個方法需要在幀中分配多大的記憶體空間是完全確定的,在方法運行期間不會改變局部變數表的大小。
  • 在Java虛擬機規範中,對這個區域規定了兩種異常狀態:如果線程請求的棧的深度大於虛擬機允許的深度,將拋出StackOverFlowError異常(棧溢出);如果虛擬機棧可以動態擴展(現在大部分Java虛擬機都可以動態擴展,只不過Java虛擬機規範中也允許固定長度的java虛擬機棧),如果擴展時無法申請到足夠的記憶體空間,就會拋出OutOfMemoryError異常(沒有足夠的記憶體)。

4、本地方法棧(Native Method Stacks):與虛擬機棧所發揮的作用是非常相似的,他們之間的區別不過是虛擬機棧為虛擬機執行Java方法(也就是位元組碼)服務,而本地方法棧則為虛擬機使用到的本地Native方法服務‘;在虛擬機規範中對本地方法棧中的使用方法、語言、數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的虛擬機(例如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二為一。本地方法棧也會拋出StackOverFlowError和OutOfmMemoryError異常。


5、Java堆(Java Heap):是Java虛擬機管理記憶體中的最大一塊;Java堆是所有線程共用的一塊記憶體管理區域。此記憶體區域唯一目的就是存放對象的實例,幾乎所有對象實例都在堆中分配記憶體。這一點在Java虛擬機規範中的描述是:所有對象實例以及數組都要在堆上分配,但是隨著JIT編譯器的發展與逃逸技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所有的對象都分配在堆上也不是變的那麼“絕對”了。詳解請學習我的:JVM之堆的體繫結構

 





您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 淺拷貝 拷貝就是複製, 就相當於把一個對象中的所有的內容, 複製一份給另一個對象, 直接複製, 或者說, 就是把一個對象的地址給了另一個對象, 他們指向相同, 兩個對象之間有共同的屬性或者方法, 都可以使用 寫一個函數,作用:把一個對象的屬性複製到另一個對象中,淺拷貝 var obj1={ age: ...
  • Vue 嵌套路由使用總結 by:授客 QQ:1033553122 開發環境 Win 10 node-v10.15.3-x64.msi 下載地址: https://nodejs.org/en/ 需求場景 如下圖,我們希望點擊導航欄不同菜單時,導航欄下方載入不同的組件,進而展示不同的頁面內容 解決方案 ...
  • 課程介紹 淺拷貝 深拷貝 | >遞歸 遍歷DOM樹 | >遞歸 晚上能夠把代碼寫出來是最好的 正則表達式 很重要的東西 元字元 寫幾個正則表達式 寫代碼 正則表達式的案例 >代碼寫出來 數組和偽數組的區別 複習 apply和call方法的使用和區別 都可以改變this指向的 使用方式: 函數名.ap ...
  • 話說印度研發了最新款的智能機器人,代號“七弟”,用於執行特殊任務。 由於開發者的大意疏忽,七弟的內核程式中存在一個隱晦的bug:當周圍播放電子音樂時,電子音樂中強烈且帶節奏的聲波會影響七弟周圍的空氣密度,進而干擾裡面電子元件的電容電壓值,當電容釋放時會執行一段固定的步行程式。但是電音中的節拍時長限制 ...
  • 遞歸案例 遞歸案例: 求一個數字各個位數上的數字的和: 123 >6 1+2+3 //遞歸案例:求一個數字各個位數上的數字的和: 123 >6 1+2+3 function getEverySum(x) { if (x < 10) { return x; } //獲取的是這個數字的個位數 retur ...
  • 遞歸 遞歸: 函數中調用函數自己, 此時就是遞歸, 遞歸一定要有結束的條件 var i = 0; function f1() { i++; if (i < 5) { f1(); } console.log("從前有個山,山裡有個廟,廟裡有個和尚給小和尚講故事"); } f1(); ...
  • 最近看了《Head First Design Patterns》這本書。正如其名,這本書講的是設計模式(Design Patterns),而這本書的第一章,講的是很重要的一些設計原則(Design Principles)。 Identify the aspects of your applicati ...
  • 緩存中間件 緩存架構的實現(下) 前言 緩存架構,說白了就是利用各種手段,來實現緩存,從而降低伺服器,乃至資料庫的壓力。 這裡把之前提出的緩存架構的技術分類放出來: 瀏覽器緩存 Cookie LocalStorage SessionStorage CDN緩存 負載層緩存 Nginx緩存模塊 Squi ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...