Java虛擬機JVM

来源:https://www.cnblogs.com/firecode7/archive/2020/07/12/13290379.html
-Advertisement-
Play Games

一、記憶體模型及分區 JVM 分為堆區和棧區,還有方法區,初始化的對象放在堆裡面,引用放在棧裡面,class 類信息常量池(static 常量和 static 變數)等放在方法區。 1、棧(Stack-線程私有) 1.1 棧的結構是棧幀組成的,調用一個方法就壓入一幀,幀上面存儲局部變數表,操作數棧,方 ...


一、記憶體模型及分區

  JVM 分為堆區和棧區,還有方法區,初始化的對象放在堆裡面,引用放在棧裡面,class 類信息常量池(static 常量和 static 變數)等放在方法區。

1.1、棧(Stack-線程私有)

 1.1.1 棧的結構是棧幀組成的,調用一個方法就壓入一幀,幀上面存儲局部變數表,操作數棧,方法出口等信息每一個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。局部變數表存放的是 8 大基礎類型加上一個引用類型,所以還是一個指向地址的指針。操作數棧的作用主要用來存儲運算結果以及運算的操作數,它不同於局部變數表通過索引來訪問,而是壓棧和出棧的方式。

  棧幀(Stack Frame)是用來存儲數據和部分過程結果的數據結構,同時也被用來處理動態鏈接(Dynamic Linking)、 方法返回值和異常分派( Dispatch Exception)。棧幀隨著方法調用而創建,隨著方法結束而銷毀——無論方法是正常完成還是異常完成(拋出了在方法內未被捕獲的異常)都算作方法結束。

 1.1.2 JVM為每個線程創建一個棧,用於存儲該線程執行方法的信息(實際參數、局部變數等),與線程的生命周期相同。

 1.1.3 棧的特性:後進先出;由系統自動分配速度快且棧是一個連續的存儲空間。

1.2、堆(Heep-線程共用)---運行時數據區

 1.2.1 是被線程共用的一塊記憶體區域,創建的對象和數組都保存在 Java 堆記憶體中,也是垃圾收集器進行垃圾收集的最重要的記憶體區域。由於現代 VM 採用分代收集演算法, 因此 Java 堆從 GC 的角度還可以細分為: 新生代(Eden 區、From Survivor 區和 To Survivor 區)和老年代。

 1.2.2 JVM只有一個堆,被所有線程所共用。

 1.2.3 堆是一個不連續的存儲空間,分配靈活但速度慢。

1.3、方法區/永久代(線程共用):

 1.3.1 主要是存儲類信息,常量池(static 常量和 static 變數),編譯後的代碼(位元組碼)等數據 (永遠不變或唯一的內容) 。

 1.3.2 我們常說的永久代(Permanent Generation), 用於存儲被 JVM 載入的類信息、常量、靜態變數、即時編譯器編譯後的代碼等數據. HotSpot VM把GC分代收集擴展至方法區, 即使用Java堆的永久代來實現方法區, 這樣 HotSpot 的垃圾收集器就可以像管理 Java 堆一樣管理這部分記憶體,而不必為方法區開發專門的記憶體管理器(永久帶的記憶體回收的主要目標是針對常量池的回收和類型的卸載, 因此收益一般很小)

 1.3.3 運行時常量池(Runtime Constant Pool)是方法區的一部分。Class 文件中除了有類的版本、欄位、方法、介面等描述等信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字常量和符號引用,這部分內容將在類載入後存放到方法區的運行時常量池中。 Java 虛擬機對 Class 文件的每一部分(自然也包括常量池)的格式都有嚴格的規定,每一個位元組用於存儲哪種數據都必須符合規範上的要求,這樣才會被虛擬機認可、裝載和執行。

 1.3.4 JVM只有一個方法區,被所有線程共用。

 1.3.5 方法區實際上也是堆,只是用來存儲類、常量相關的信息。

1.4、本地方法棧(線程私有)

 本地方法區和 Java Stack 作用類似, 區別是虛擬機棧為執行 Java 方法服務, 而本地方法棧則為Native 方法服務, 如果一個 VM 實現使用 C-linkage 模型來支持 Native 調用, 那麼該棧將會是一個C 棧,但 HotSpot VM 直接就把本地方法棧和虛擬機棧合二為一。

1.5、程式計數器(線程私有)

 一塊較小的記憶體空間, 是當前線程所執行的位元組碼的行號指示器,每條線程都要有一個獨立的程式計數器,這類記憶體也稱為“線程私有”的記憶體。正在執行 java 方法的話,計數器記錄的是虛擬機位元組碼指令的地址(當前指令的地址)。如果還是 Native 方法,則為空。這個記憶體區域是唯一一個在虛擬機中沒有規定任何 OutOfMemoryError 情況的區域。

二、Minor GC、Major GC、Full GC

2.1 Minor GC

 新生代 GC(Minor GC):從年輕代空間(包括 Eden 和 Survivor 區域)回收記憶體被稱為 Minor GC,因為 Java 對象大多都具備朝生夕滅的特性,所以 Minor GC 非常頻繁,一般回收速度也比較快。這一定義既清晰又易於理解。但是,當發生Minor GC事件的時候,有一些有趣的地方需要註意到:

  2.1.1  當 JVM 無法為一個新的對象分配空間時會觸發 Minor GC,比如當 Eden 區滿了。所以分配率越高,越頻繁執行 Minor GC。

  2.1.2  記憶體池被填滿的時候,其中的內容全部會被覆制,指針會從0開始跟蹤空閑記憶體。Eden 和 Survivor 區進行了標記和複製操作,取代了經典的標記、掃描、壓縮、清理操作。所以 Eden 和 Survivor 區不存在記憶體碎片。寫指針總是停留在所使用記憶體池的頂部。

  2.1.3 執行 Minor GC 操作時,不會影響到永久代。從永久代到年輕代的引用被當成 GC roots,從年輕代到永久代的引用在標記階段被直接忽略掉。

  2.1.4 所有的 Minor GC 都會觸發“全世界的暫停(stop-the-world)”,停止應用程式的線程。對於大部分應用程式,停頓導致的延遲都是可以忽略不計的。其中的真相就 是,大部分 Eden 區中的對象都能被認為是垃圾,永遠也不會被覆制到 Survivor 區或者老年代空間。如果正好相反,Eden 區大部分新生對象不符合 GC 條件,Minor GC 執行時暫停的時間將會長很多。
所以 Minor GC 的情況就相當清楚了——每次 Minor GC 會清理年輕代的記憶體。

  2.1.5 觸發機制:當年輕代滿時就會觸發Minor GC,這裡的年輕代滿指的是Eden代滿,Survivor滿不會引發GC。

2.2 Major GC

 Major GC清理Tenured區,用於回收老年代,出現Major GC通常會出現至少一次Minor GC。

 Major GC的觸發條件:當年老代空間不夠用的時候,虛擬機會使用“標記—清除”或者“標記—整理”演算法清理出連續的記憶體空間,分配對象使用。

  註意:也有認為是和full GC是等價的,收集整個GC堆。但因為HotSpot VM發展了這麼多年,外界對各種名詞的解讀已經完全混亂了,當有人說“major GC”的時候一定要問清楚他想要指的是上面的old GC(只清理老年代)還是 full GC。

2.3 Full GC

 Full GC是針對整個新生代、老生代、元空間(metaspace,java8以上版本取代perm gen)的全局範圍的GC。Full GC不等於Major GC,也不等於Minor GC+Major GC,發生Full GC需要看使用了什麼垃圾收集器組合,才能解釋是什麼樣的垃圾回收。

 Full GC觸發條件

  2.3.1 調用System.gc時,系統建議執行Full GC,但是不必然執行

  2.3.2 老年代空間不足

  2.3.3 方法去空間不足

  2.3.4 通過Minor GC後進入老年代的平均大小大於老年代的可用記憶體

  2.3.5 由Eden區、From Space區向To Space區複製時,對象大小大於To Space可用記憶體,則把該對象轉存到老年代,且老年代的可用記憶體小於該對象大小

三、JVM運行時記憶體

   Java 堆從 GC 的角度還可以細分為: 新生代(Eden 區、From Survivor 區和 To Survivor 區)和老年代。    

3.1、新生代

  是用來存放新生的對象。一般占據堆的 1/3 空間。由於頻繁創建對象,所以新生代會頻繁觸發MinorGC 進行垃圾回收。新生代又分為 Eden 區、ServivorFrom、ServivorTo 三個區。

 3.1.1 Eden 區

  Java 新對象的出生地(如果新創建的對象占用記憶體很大,則直接分配到老年代)。當 Eden 區記憶體不夠的時候就會觸發 MinorGC,對新生代區進行一次垃圾回收。

 3.1.2 ServivorFrom 區

  上一次 GC 的幸存者,作為這一次 GC 的被掃描者。

 3.1.3 ServivorTo區

  保留了一次 MinorGC 過程中的幸存者。

 3.1.4 MinorGC 的過程(複製->清空->互換)

  MinorGC 採用複製演算法。

  3.1.4.1 eden、servivorFrom 複製到 ServivorTo,年齡+1

    首先,把 Eden 和 ServivorFrom 區域中存活的對象複製到 ServivorTo 區域(如果有對象的年齡已經達到了老年的標準,則賦值到老年代區),同時把這些對象的年齡+1(如果 ServivorTo 不夠位置了就放到老年區);虛擬機會給每個對象定義一個對象年齡(Age)計數器,對象在Survivor區中每“熬過”一次GC,年齡就會+1。待到年齡到達一定歲數(預設是15歲),虛擬機就會將對象移動到年老代。

  3.1.4.2 清空 eden、servivorFrom

    然後,清空 Eden 和 ServivorFrom 中的對象;

  3.1.4.3 ServivorTo 和 ServivorFrom 互換

    最後,ServivorTo 和 ServivorFrom 互換,原 ServivorTo 成為下一次 GC 時的 ServivorFrom區。

3.2、老年代

 主要存放應用程式中生命周期長的記憶體對象。

 老年代的對象比較穩定,所以 MajorGC 不會頻繁執行。在進行 MajorGC 前一般都先進行了一次 MinorGC,使得有新生代的對象晉身入老年代,導致空間不夠用時才觸發。當無法找到足夠大的連續空間分配給新創建的較大對象時也會提前觸發一次 MajorGC 進行垃圾回收騰出空間。

 MajorGC 採用標記清除演算法:首先掃描一次所有老年代,標記出存活的對象,然後回收沒有標記的對象。MajorGC 的耗時比較長,因為要掃描再回收。MajorGC 會產生記憶體碎片,為了減少記憶體損耗,我們一般需要進行合併或者標記出來方便下次直接分配。當老年代也滿了裝不下的時候,就會拋出 OOM(Out of Memory)異常。

 

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

-Advertisement-
Play Games
更多相關文章
  • 函數防抖和節流都是對高頻動作觸發回調函數的一個優化,實現方式上有類似之處。先從使用場景做個區分。 防抖使用場景: 表單輸入框校驗 提交按鈕避免重覆提交 節流使用場景: scroll,mousemove,resize等 函數防抖(debounce) 表單輸入框校驗在用戶不停的打字輸入時並不需要向後臺校 ...
  • 前言 在4月21日晚,Vue作者尤雨溪在嗶哩嗶哩直播分享了Vue.js 3.0 Beta最新進展。 裡面尤大大所提到他最近在做的這個小工具 vite ,一個實驗性的no build的vue開發伺服器。(這個小工具可以支持熱更新,且不用預編譯) 一丶安裝 命令行複製以下 mkdir vue-vite  ...
  • 1 #include <stdio.h> 2 3 void createbtree(int *btree,int *data,int len) 4 { 5 int level; //樹的層數 6 int i; 7 8 btree[1] = data[1]; //創建根節點 9 for( i = 2; ...
  • python virtualenv虛擬環境配置與使用 By:賴富玉 QQ:1033553122 概述 python開發過程中,我們可能需要同時開發多款應用,這些應用可能公用同一個版本的Python程式,但是使用不同版本的第三方庫,比如A應用使用six 1.12.0,而B應用需要使用six 1.15. ...
  • 最近一直在研究AQS的源碼,希望可以更深刻的理解AQS的實現原理。雖然網上有很多關於AQS的源碼分析,但是看完以後感覺還是一知半解。於是,我將自己的整個理解過程記錄下來了,希望對大家有所幫助。 基本原理 AQS是Java中鎖的基礎,主要由兩個隊列組成。一個隊列是同步隊列,另一個是條件隊列。 同步隊列 ...
  • 為了方便以後配置新的windows電腦java、idea,所以專門記錄一下 1:JDK JDK是 Java 語言的軟體開發工具包,主要用於移動設備、嵌入式設備上的java應用程式。JDK是整個java開發的核心,它包含了JAVA的運行環境(JVM+Java系統類庫)和JAVA工具。所以首先要配置好j ...
  • 描述Python的變數聲明,可覷其語言設計思路,實現更快地代碼閱讀。 變數聲明 C# public、protect、private、internal 明確指出適用範圍 (完全公開、子類可訪問、僅自己可訪問、程式集內可訪問) Python 有點神奇,沒有不能訪問的變數,一般通過“潛規則”暗示其私有性 ...
  • pyenv 簡介 pyenv 是 Python 版本管理工具。 pyenv 可以改變全局的 Python 版本,在系統中安裝多個版本的 Python, 設置目錄級別的 Python 版本,還能創建和管理 virtual python environments。 安裝 pyenv 安裝git:~]# ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...