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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...