深入理解JVM之JVM記憶體區域與記憶體分配

来源:https://www.cnblogs.com/furaywww/archive/2018/03/14/8555595.html
-Advertisement-
Play Games

以下基本不是原創,都是轉載。 JVM運行時,首先需要類載入器(ClassLoader) 載入所需類的位元組碼,載入完畢交由執行引擎執行,執行過程中需要一段空間來存儲數據(類比CPU與主存)。這段記憶體空間的分配和釋放過程正是我們所關心的,稱為運行時數據區。 運行時數據區 如上圖所示,運行時數據區包括:程 ...


以下基本不是原創,都是轉載。

 

JVM運行時,首先需要類載入器(ClassLoader) 載入所需類的位元組碼,載入完畢交由執行引擎執行,執行過程中需要一段空間來存儲數據(類比CPU與主存)。這段記憶體空間的分配和釋放過程正是我們所關心的,稱為運行時數據區

運行時數據區

如上圖所示,運行時數據區包括:程式計數器(即PC寄存器),Java 虛擬機棧(VM Stack),Java 堆(Heap),方法區(Method Area),本地方法棧(Native Method Stack)。下麵帶領大家深入理解各個數據區域

JVM實際上就是一臺虛擬的電腦,目的是為了實現"一次編譯,處處執行"。所以,在理解運行時數據區時,完全可以與操作系統系統 記憶體,寄存器類比學習。

2.2.1 程式計數器

程式計數器是一塊較小的記憶體區域,作用可以看做是當前線程執行的位元組碼的位置指示器。分支、迴圈、跳轉、異常處理和線程恢復等基礎功能都需要依賴這個計算器來完成

註意,Java虛擬機中的程式計數器指向正在執行的位元組碼地址,而不是下一條。

每條線程都有獨立的計數器,保證線程切換恢復正確位置,因此程式計數器這一塊記憶體區域是線程隔離的。該區域是唯一一個沒有規定任何OutOfMemoryError的區域

2.2.2 Java虛擬機棧(VM Strack

虛擬機棧也叫棧記憶體,是線上程創建時創建,是線程私有的,它的生命期是跟隨線程的生命期,線程結束棧記憶體也就釋放,對於棧來說不存在垃圾回收問題,只要線程一結束,該棧就 Over,所以不存在垃圾回收也有一些資料翻譯成JAVA方法棧,大概是因為它所描述的是java方法執行的記憶體模型。

每個方法執行的同時創建幀棧(Strack Frame)用於存儲局部變數表(包含了對應的方法參數和局部變數),操作棧(Operand Stack,記錄出棧、入棧的操作),動態鏈接方法出口等信息。每個方法被調用直到執行完畢的過程,對應這幀棧在虛擬機棧的入棧和出棧的過程。

 

棧幀是一個記憶體區塊,是一個數據集,一個有關方法(Method)和運行期數據的數據集,我們看一個圖來理解一下 Java棧,遵循“先進後出”原則。如下圖所示:

 

大多數人說的stack棧記憶體,就是指虛擬機棧中局部變數表部分

局部變數表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象的引用(reference類型,不等同於對象本身,根據不同的虛擬機實現,可能是一個指向對象起始地址的引用指針,也可能是一個代表對象的句柄或者其他與對象相關的位置)和 returnAdress類型(指向下一條位元組碼指令的地址)。局部變數表所需的記憶體空間在編譯期間完成分配,在方法在運行之前,該局部變數表所需要的記憶體空間是固定的,運行期間也不會改變。

異常

  1. 當線程請求的棧深度大於所允許的深度,拋出StackOverflowError異常。
  2. 長度不夠時,虛擬機棧可進行動態擴展,申請記憶體。若無法申請到足夠的記憶體,拋出OutOfMemoryError異常。

2.2.3 本地方法棧(Native Method Stack

1.本地方法棧與虛擬機棧類似,區別是虛擬機棧記錄執行的Java方法(也就是位元組碼),本地方法棧則記錄Native方法。

2.在HotSpot虛擬機將本地方法棧和虛擬機棧合二為一。

3.本地方法棧同樣會拋出StackOverflowErrorOutOfMemoryError異常。

2.2.4 Java堆(Heap)

1.Java 堆是被所有線程共用的一塊記憶體區域,在虛擬機啟動時創建。

2.JVM里所管理記憶體最大的一塊,幾乎所有對象實例以及數組都在堆上,類的成員變數也是在堆上。(類的成員變數單指基本變數的引用??還沒弄清晰等更正)

3/Java堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可,就像我們的磁碟空間一樣。

 記憶體模型

這塊區域是垃圾收集器管理的主要區域("GC 堆 ")。現在收集器基本都是採用分代收集演算法:新生代採用複製演算法,老年代採用標記清理演算法。從記憶體回收的角度,Java堆可以分為新生代(Young Generation)與老生代(Old Generation)。這種劃分的方式,是為了更好的回收記憶體(老生代記憶體會被優先回收)。

image

如圖,新生代還可以分為Eden空間From Survivor空間To Survivor空間

永久代(Permanent Generation)用於存儲靜態類型數據,與垃圾收集器關係不大。

註意:本圖展示的是JVM堆的記憶體模型,JVM堆記憶體包括Java堆區域 和 永久代區域。因此,永久代不屬於Java堆

異常

Java堆同樣可擴展(-Xmx與-Xms參數)。若堆中記憶體已無法為對象實例分配且無法再擴展,拋出OutOfMemoryError異常。

 

2.2.5 方法區(Method Area

方法區也叫永久代,在過去(自定義類載入器還不是很常見的時候),類大多是”static”的,很少被卸載或收集,因此被稱為“永久的(Permanent)”。

也被稱為Non-Heap(非堆),被所有的線程共用的一塊記憶體區域。它用於存儲已被虛擬機載入的類信息(Object Class Data(載入類的類定義數據) )、常量、靜態變數、即時編譯器(JIT)編譯後的代碼等數據。

方法區也可以是記憶體不連續的區域組成的,並且可設置為固定大小,也可以設置為可擴展的,這點與堆一樣。

垃圾回收在這個區域會比較少出現,這個區域記憶體回收的目的主要針對常量池的回收和類的卸載(後面會提到)。

 

2.2.6 運行時常量池(Runtime Constant Pool)

運行時常量池是方法區的一部分。在位元組碼文件(Class文件)中,除了有類的版本、欄位、方法、介面等先關信息描述外,還有常量池(Constant Pool Table)信息,用於存儲編譯器產生的字面量和符號引用。這部分內容在類被載入後,都會存儲到方法區中的RCP。   值得註意的是,運行時常量池相對於CLass文件常量池的另外一個重要特征是具備動態性,所以運行時產生的新常量也可以被放入常量池中,比如 String 類中的 intern() 方法產生的常量。
package intern;

public class Main1 {
    public static void main(String[] args) {
        String s0= "I'm coding";   
        String s1=new String("I'm coding");   
        String s2=new String("I'm coding");   
        System.out.println( s0==s1 );  
        System.out.println( s0==s1.intern());   
        s2=s2.intern();  
        System.out.println( s0==s2 );   
          
    }
}

輸出結果

false
true
true

本例中,s0直接保存在常量池,s1與s2的對象實例存儲在Java堆中。==直接比較對象的hashCode,因此第一行輸出false。s1.intern()方法返回s1在常量池中的引用,沒有則創建。
s1存放的字元串已經在常量池中存在,直接返回s0的引用,第二行輸出true
同理,s2接收了s2.intern()的返回值,字元串值與s0相同,第三行輸出true

  常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)對其他類型、方法、欄位的符號引用.例如: ◆類和介面的全限定名; ◆欄位的名稱和描述符; ◆方法和名稱和描述符。   池中的數據和數組一樣通過索引訪問。由於常量池包含了一個類型所有的對其他類型、方法、欄位的符號引用,所以常量池在Java的動態鏈接中起了核心作用.   很有用且重要關於常量池的擴展:Java常量池詳解 http://www.cnblogs.com/DreamSea/archive/2011/11/20/2256396.html   運行時常量池是方法區的一部分,因此受方法區記憶體的限制。當無法申請到記憶體時,拋出OutOfMemoryError異常。

2.2.7 直接記憶體

直接記憶體區並不是 JVM 管理的記憶體區域的一部分,而是其之外的。該區域也會在 Java 開發中使用到,並且存在導致記憶體溢出的隱患,如果你對 NIO 有所瞭解,可能會知道 NIO 是可以使用 Native Methods 來使用直接記憶體區的。

在 JDK 1.4 中新加入了 NIO 類,引入了一種基於通道(Channel)與緩衝區(Buffer)的 I/O 方式,它可以使用 Native 函數庫直接分配堆外記憶體,然後通過一個存儲在 Java 堆里的 DirectByteBuffer 對象作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在 Java 堆和 Native 堆中來回覆制數據。

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

-Advertisement-
Play Games
更多相關文章
  • 忙得忘了更新了 經過了半年多的糾結終於還是一衝動買了一隻緬因貓,又給自己找了個長期工作,我也是夠能作的了! 貓和狗完全不一樣,各種不一樣,不交流,沒有反應,沒有表情, 還要給它清理大小便,它到處爬,把我蘋果原裝數據線咬壞了, 白天睡晚飯上上竄下跳,還經常用爪子撩狗,養了這幾個禮拜, 我現在渾身上下都 ...
  • 回顧 int/float/str/list/tuple/dict 整數型和浮點型是不可變的,不是序列 字元串是不可變的,是序列 列表是可變的,是序列 元組是不可變的,是序列 字典是可變得,但不是序列 集合的基本概念 集合是基本的數學概念,它是集合論的研究對象,指具有某種特定性質的事物的總體,(在最原 ...
  • 給定一個有1編號。進行搜索時,假設我們總是從編號最小的頂點出發,按編號遞增的順序訪問鄰接點。 輸入格式: 輸入第1行給出2個整數N(0<N≤10)和E,分別是圖的頂點數和邊數。隨後E行,每行給出一條邊的兩個端點。每行中的數字之間用1空格分隔。 輸出格式: 按照{v1v2.....vk}的格式,每行輸 ...
  • 內容:判斷質數 持續更新 # __author: _nbloser # date: 2018/2/4 import math def is_prime(number): num_sqrt = int(math.sqrt(number)) for i in range(2, num_sqrt + 1) ...
  • 使用模板有助於將業務邏輯與表現邏輯分開,更易於維護。模板是已經建立的網頁代碼,其中部分動態數據需要在請求的上下文中用具體值替換。 flask中使用了Jinja2模板引擎,儲存在templates文件夾中。 使用 {{ name }} 占位 模板的渲染 模板的渲染即用真實值取代模板中的占位變數的過程。 ...
  • 1.在pom.xml中使用spring-boot-starter-parent的作用: Maven users can inherit from the spring-boot-starter-parent project to obtain sensible defaults. The paren ...
  • 內容:通過修改hosts文件,讓pycharm不能夠聯網驗證激活碼的方式 1、修改hosts文件 文件位置:C:\Windows\System32\drivers\etc 在文件末尾添加:0.0.0.0 account.jetbrains.com 如圖: 2、打開PyCharm,選擇 Activat ...
  • 某地區經過對城鎮交通狀況的調查,得到現有城鎮間快速道路的統計數據,並提出“暢通工程”的目標:使整個地區任何兩個城鎮間都可以實現快速交通(但不一定有直接的快速道路相連,只要互相間接通過快速路可達即可)。現得到城鎮道路統計表,表中列出了任意兩城鎮間修建快速路的費用,以及該道路是否已經修通的狀態。現請你編 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...