Java虛擬機——JVM

来源:https://www.cnblogs.com/ZekiChen/archive/2020/02/20/12319401.html
-Advertisement-
Play Games

一、JVM整體架構 1、JVM(Java虛擬機):指以軟體的方式模擬具有完整硬體系統功能、運行在一個完全隔離環境中的完整電腦系統,是物理機的軟體實現。常用的虛擬機有VMWare、Virtual Box、Java Virtual Machine。 2、JVM由三個主要的子系統構成 類載入子系統 (即 ...


一、JVM整體架構

1、JVM(Java虛擬機):指以軟體的方式模擬具有完整硬體系統功能、運行在一個完全隔離環境中的完整電腦系統,是物理機的軟體實現。常用的虛擬機有VMWare、Virtual Box、Java Virtual Machine。

2、JVM由三個主要的子系統構成

  • 類載入子系統 (即類載入器)
  • 運行時數據區(即記憶體結構 / 記憶體模型 / JMM)
  • 執行引擎(包含垃圾收集器)

通過類載入器將.class文件載入進記憶體中,再由執行引擎去運行。

堆和方法區是所有線程都共用的。

Java棧、本地方法棧和程式計數器是非線程共用的。

二、JVM記憶體結構

下麵會用到的例子:定義一個Math類。

1、本地方法棧(線程私有):登記native本地方法(即native方法是存到本地方法棧),在執行引擎執行時載入本地方法庫(C語言實現的庫)。

舉例:Thread類中的 start0() 方法底層實現是用C語言寫的。

2、程式計數器(線程私有):就是一個指針,指向方法區中的方法位元組碼(用來存儲指向下一條指令的地址,也即指向將要執行的指令代碼),由執行引擎讀取下一條指令,是一個非常小的記憶體空間,幾乎可以忽略不計。

舉例:對.class文件進行 javap -c 反編譯,下圖為 math() 方法反編譯後的結果:(iconst_1和istore_1兩條指令代表 int a=1)

3、方法區(線程共用):類的所有欄位和方法位元組碼,以及一些特殊方法如構造函數、介面代碼也定義在此(類載入器會將位元組碼文件載入到方法區中,分解成多個部分)。簡單說,所有定義的方法的信息都保存在該區域,靜態變數+常量+類信息(構造方法/介面定義)+運行時常量池都存在方法區中,雖然JVM規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的應該是與Java堆區分開來。

4、Java棧(線程私有)Java線程執行方法的記憶體模型,一個線程對應一個棧,每個方法在執行的同時都會創建一個棧幀(用於存儲局部變數表、操作數棧、動態鏈接、方法出口等信息),不存在垃圾回收問題,只要線程一結束該棧就釋放,生命周期和線程一致。

JVM對該區域規範了兩種異常:

① 線程請求的棧深度大於虛擬機棧所允許的深度時,將拋出StackOverFlowError異常。

② 若虛擬機棧可動態擴展,當無法申請到足夠記憶體空間時將拋出OutOfMemoryError,通過JVM參數 -> Xss指定棧空間,空間大小決定函數調用的深度。

下圖左邊為Java棧的記憶體結構圖:

動態鏈接:如Map map = new HashMap(),程式運行時map變數需要去找到運行時的HashMap實例對象(多態)的過程,就叫動態鏈接。

方法出口:如main()方法中的math()方法運行結束return返回的值用於main()方法中,return的這個過程就叫方法出口。

5、堆(線程共用): 虛擬機啟動時創建,用於存放對象實例,幾乎所有的對象(包含常量池)都放在堆上分配記憶體,當對象無法在該空間申請到記憶體時將拋出OutOfMemoryError異常。同時也是垃圾收集器管理的主要區域。可通過 -Xmx -Xms 參數來分別指定最大堆和最小堆。

下圖為堆的記憶體結構圖:

JVM調優的根本目的:儘量減少Full GC的次數,並且縮短每次Full GC的時間長度。(Full GC性能非常低,執行這個過程時會停止整個JVM,即STW(Stop The World),包括程式運行的那些線程,然後專門去做垃圾收集。現在新的GC會儘量縮短STW時間長度,儘量讓垃圾收集和業務線程併發執行)

垃圾收集器(GC)存在的意義:回收堆中無引用的對象,釋放空間

堆中新生代(Young Generation)占1/3的堆空間,新生代包括伊甸園區(Eden Space)和幸存者區(Survivor Space);老年代(Old Generation)占2/3的堆空間。

JDK1.8以前是沒有元數據區(MetaData Space)的,而是永久代,從1.8開始元空間取代了永久代,本質和永久代類似,都是對JVM規範中方法區的實現,區別在於元數據區並不在虛擬機中,不屬於堆中的記憶體結構,而是直接使用本機物理記憶體,永久代在虛擬機中,邏輯結構上屬於堆,但是物理上不屬於堆,堆大小=新生代+老年代。元數據區也有可能發生OutOfMemory異常。

  • JDK1.6及之前:有永久代,常量池在方法區
  • JDK1.7:有永久代,但已逐步“去永久代”,常量池在堆
  • JDK1.8及之後:無永久代,常量池在元空間

提問:為什麼JDK1.8用元數據區取代了永久代?

官方解釋:移除永久代是為融合HotSpot JVM與JRockit VM而做出的努力,因為JRockit沒有永久代,不需要配置永久代。

(JDK 8實際上是這兩種虛擬機合併之後的產物,HotSpot JVM(Sun公司開發),JRockit VM(BEA公司開發)。猜測:HotSpot JVM輸了,沒錯,開發出Java語言的Sun公司最後輸了,就聽JRockit VM的)

new出來的對象會放在Eden區中,當Eden區占滿時會做一次Minor GC(即輕GC),回收Eden區中無引用的對象,剩下的存活對象則會放到From區中。

② 後面又有新的new出來的對象不斷存放在Eden區中,當Eden區占滿時再做Minor GC,又有對象存放在From區中,當From區占滿時也會做Minor GC,GC會回收Eden區和From區中無引用的對象,剩下的存活對象則會放到To區中,此時角色轉變,From區變成To區,To區變成From區。

③ 接著,還會有新的對象存放到Eden區中,當Eden區占滿時再做Minor GC,此時存活的對象放到新的From區中,當新的From區放滿時又做Minor GC,把存活對象放入新的To區,依次輪循。

④ 如果一直有新的對象過來,不斷的做Minor GC,當幸存者區的From區和To區輪循大概15次時,如果To區還有存活的對象,再做一次Minor GC則會把存活的對象移入老年代。

如果有一天老年代也占滿了,則會觸發Full GC再次回收無引用對象(有的GC會回收所有區,有的只會回收老年代,得看使用了哪種GC,後面會講)。

三、JVM執行引擎

JVM執行引擎:讀取運行時數據區的Java位元組碼並逐個執行。

解釋執行位元組碼的方式:① JIT編譯器;② 位元組碼解釋器;③ mixed mode(前兩種的混合模式,JDK 8是採用這種,之前的我不知道)

JIT編譯器(Just In Time,即時編譯):一次性解釋所有指令,第一次執行慢,後面執行快。(會緩存)

位元組碼解釋器:逐行解釋指令,每次執行需要重新解釋,前幾次可能比JIT編譯器快,後面比它慢。(不緩存)

 


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

-Advertisement-
Play Games
更多相關文章
  • 變數提升 聲明的變數會提升到函數或全局作用域頂部 簡單例子 函數提升 函數寫法:函數表達式、函數聲明、Function構造函數(這種不推薦).其中函數表達式不會 函數提升 , 函數聲明 會函數提升。 我們都知道程式在執行時是從上往下執行的,而這裡 在定義之前就調用了為什麼不報錯? 實例一 值為多少? ...
  • 1、首先是設計稿 2、然後使用PxCook進行尺寸標註 3、字體信息去PS里看 4、首頁框架代碼編寫 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> <lin ...
  • var eleLink = document.createElement('a'); eleLink.href = "/wordpress/?p=9227"; console.log(eleLink.href); ...
  • 提到new,肯定會和類和實例聯繫起來,如: function Func() { let x = 100; this.num = x + } let f = new Func(); 上面的代碼,我們首先創建了一個函數,如果是用面向對象的說法就是創建了一個Function類的實例,如果直接執行這個函數, ...
  • FOUC(Flash Of Unstyled Content)即瀏覽器樣式閃爍或者叫做無樣式記憶體閃爍(用戶定義樣式表載入之前瀏覽器使用預設樣式顯示文檔,用戶樣式載入渲染之後再從新顯示文檔,造成頁面閃爍。) 解決方法:用link載入css文件,放在head標簽裡面。 ...
  • Vue中的$Bus使用 將Bus單獨抽離成一個文件 Bus.js 創建兩個兄弟組建 C2.vue C1.vue index.vue 註意:這種引入方式,經過webpack打包後可能會出現Bus局部作用域的情況,即引用的是兩個不同的Bus,導致不能正常通信 將Bus註入到Vue的prototype上 ...
  • 我們知道STL中我們常用的 與`multiset map multimap _Rb_tree _Rb_tree`的各個參數的確定。 特別註意在如下代碼的 類用於從 中選出用於排序的key值,這個仿函數必須返回 而不能是 ,否則 會拋出 。由於源碼中邏輯比較複雜,但是可以觀察到內部涉及這方面的地方經常 ...
  • 多線程 1、程式、進程、線程的理解 1.程式(program) 概念:是為了完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼塊。 2.線程(process) 概念:程式的一次執行過程,或是正在運行的一個程式。 說明:進程作為資源分配的單位,系統在運行時會為每個進程分配不同的記憶體區域。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...