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
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...