JVM中的五大內存區域劃分詳解及快速掃盲

2020-12-19 計算機java編程

一、快速掃盲

1. JVM是什麼

JVM是JavaVirtualMachine的縮寫,即咱們經常提到的Java虛擬機。虛擬機是一種抽象化的計算機,有著自己完善的硬體架構,如處理器、堆棧等,具體有什麼咱們不做了解。目前我們只需要知道想要運行Java文件,必須先通過一個叫javac的編譯器,將代碼編譯成class文件,然後通過JVM把class文件解釋成各個平臺可以識別的機器碼,最終實現跨平臺運行代碼。

2. JDK、JRE、JVM之間的關係

JDK:全稱為Java Development Kit,漢語為java開發工具包,即所有有關java的東西都包含在裡面,比如運行環境JRE、java的核心代碼、JVM等等。JRE:全稱為Java Runtime Environment,漢語為java運行環境,即想要運行java文件必須先有java的環境才行,jre就是提供了這麼一個環境。JVM:上面已經提到了JVM,它是java最核心的部分。簡單用一張圖來理解這三個的關係:

3. jvm的組成成分

不了解jvm的同學看到這張圖後可能會有點懵逼,不過沒關係,放這張圖只是想讓你了解jvm中有三塊內容非常重要,1.java代碼如何執行?2.內存如何管理?3.線程資源如何利用?腦袋裡有個印象即可,帶著問題去學習。

4. 運行java文件的大概流程

想要運行java的源文件,必須要經過javac編譯器編譯成.class文件,也就是字節碼文件。然後通過jvm中的解釋器,解釋成特定機器上的機器碼。每種機器上的解釋器是不一樣的,我們經常用的也就是windows和linux系統,這也是為什麼java能夠跨平臺的原因。當一個程序從開始運行,虛擬機就開始實例化,多個程序運行就會存在多個虛擬機實例,程序退出或者關閉,虛擬機實例也將隨之消亡,多個虛擬機之間的數據是不共享的。

二、JVM運行時數據區

1. 運行時數據區域組成

虛擬機在執行java程序時,會將自己管理的內存劃分為幾個區域,每個區域都有自己的用途,並且創建時間和銷毀時間也不一樣。在程序運行時的內存區域主要可以劃分為五個,分別是:方法區、堆、虛擬機棧、本地方法棧、程序計數器。可以用下面的圖來描述:

2. Java堆

Java堆是java虛擬機所管理的內存中最大的一塊,是被所有線程都共享的內存區域。存在的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裡進行分配內存。不過目前隨著技術的不斷發展,也並不是所有的對象實例都在堆中分配內存,可能也存在棧上分配。由於所佔空間大,又存放各種實例對象,因此java虛擬機的垃圾回收機制主要管理的就是此區域,詳細的垃圾回收方法以後會提到。JVM規範中規定堆可以處於物理上不連續的內存空間中,只要邏輯上是連續的即可。並且可以通過-Xmx和-Xms來擴展堆的內存大小,如果在堆中沒有足夠的內存為實例分配,並且堆也無法在擴展時,就會報OutOfMemoryError異常。

3 方法區

跟Java堆一樣,方法區是各個線程共享的內存區域,此區域是用來存儲類的信息(類的名稱、欄位信息、方法信息)、靜態變量、常量以及編譯器編譯後的代碼。JVM規範中並不區分方法區和堆,只把方法區描述為堆的邏輯部分,但是它卻有一個別名叫做非堆(Non-Heap),目的就是與Java堆區分開。根據垃圾回收機制中分代回收的思想,如果在HotSpot虛擬機上開發,可以把方法區稱為「永久代」(只是可以這麼理解,但實質是不一樣的),垃圾回收機制在Java堆中劃分一個部分稱為永久代,用此區域來實現方法區,這樣HotSpot的垃圾收集器就可以像管理Java堆一樣管理這部分內存,而不必為方法區開發專門的內存管理器。

運行時常量池

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

4. 程序計數器

雖然在上圖中程序計數器的面積很大,但實際上它是一塊較小的內存空間,可以看作當前線程所執行字節碼的行號指示器。字節碼解釋器在工作中時下一步該幹啥、到哪了,就是通過它來確定的。大家都知道在多線程的情況下,CPU在執行線程時是通過輪流切換線程實現的,也就是說一個CPU處理器(假設是單核)都只會執行一條線程中的指令,因此為了線程切換後能恢復到正確的執行位置,每個線程都要有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲,我們稱這類內存區域為「線程私有」的內存。

很明顯,程序計數器就是線程私有的。如果線程正在執行的是一個java方法,程序計數器記錄的是正在執行的虛擬機字節碼指令地址;如果執行的Native方法,程序計數器記錄的值為空(Undefined),此內存區域是java中唯一一個在java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。

5. Java虛擬機棧

我們經常會把java內存粗糙的分為兩個部分,堆和棧,Java虛擬機棧就是棧這一部分,或者說是虛擬機棧中局部變量表部分。跟程序計數器一樣,虛擬機棧也是線程私有的,它的生命周期跟線程相同。每個方法在執行的同時都會創建一個棧幀(Stack Frame),每個棧幀對應一個被調用的方法,棧幀中用於存儲局部變量表、操作數棧、動態鍊表、方法出口等信息。每一個方法從開始執行到結束就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。

局部變量表:顧名思義,他就是用來存儲方法中的局部變量(包括在方法中生命的非靜態變量以及函數形參),對於基本數據類型,直接存值,對於引用類型的變量,存儲指向該對象的引用。由於它只存放基本數據類型的變量、引用類型的地址和返回值的地址,這些類型所需空間大小已知且固定,所以當進入一個方法時,這個方法需要在棧幀中分配多大的局部變量空間是完全可以確定的,在方法運行期間也不會改變局部變量表的大小。指向運行常量池的引用:在方法執行過程中難免會使用到類中定義的常量,因此棧幀中要存放一個指向運行時常量池的引用。方法返回地址:當一個方法執行結束後,要返回到之前調用它的地方,因此在棧幀中需要保存一個方法返回地址。6. 本地方法棧

本地方法棧與虛擬機棧的功能非常的相似,區別不過是虛擬機棧為虛擬機執行java方法服務,而本地方法棧為虛擬機執行Native方法服務。有的虛擬機並不會區分本地方法棧和虛擬機棧,比如Sun HotSpot虛擬機直接將兩個合二為一。

7. 用一張圖總結

相關焦點

  • JVM內存區域之線程私有區域
    不過,也正是java把控制內存的權力交給了java虛擬機,一旦出現內存洩漏和內存溢出方面的問題,如果不了解虛擬機是怎麼使用內存的,那排查錯誤、修正問題將會成為一項異常艱難的工作。運行時數據區:java虛擬機在執行java程序的過程中會把它所管理的內存劃分為若干個不同的數據區域。
  • JVM-概述和內存區域
    方法區和堆區是所有線程共享的內存區域;Java棧又叫做jvm虛擬機棧。執行引擎等同於翻譯class文件的語言翻譯器。方法區(永久代)在jdk8中又叫做元空間Metaspace運行時數據區概述堆內存:保存所有引用數據的真實信息;棧內存:基本類型、運算、指向堆內存的指針;方法區:所以定義的方法的信息都保存方法區中,屬於共享區
  • java線程前傳——jvm內存結構、內存模型和cpu結構
    ,這個過程是少不了的一個線程肯定是要運行在一個核上的,多個線程可以運行在不同的核上,這個時候,因為緩存的存在,如果沒有同步機制,那一個線程修改了緩存的數據,另一個線程也修改了緩存的數據,這個時候這兩個線程修改後的數據都需要寫入到內存當中,就會出現問題jvm為了方便,將這些緩存抽象出來,構造了自己的內存模型,即主內存和工作內存的數據交互,即java 內存模型(jmm)
  • 非洲的地理區域劃分,「東南西北中」五大區域該怎樣劃分?
    區域是研究地理問題的基本載體,我們所研究的自然或者人文地理問題,歸根到底實際上是在研究某一區域內的地理問題。當然,區域的範圍可大可小,也就是區域的尺度有大有小,地理區域的劃分方法有很多,包括政區、氣候、地形、自然帶、河流水系等等,都可以作為區域劃分的依據。
  • 聊到JVM(還怕面試官問JVM嗎?)
    進入本地方法棧,調用本地方法接口JNI,拓展Java的使用,融合不同的語言為Java所用Java誕生的時候C、C++橫行,為了立足,必須要能調用C、C++的程序於是在內存區域中專門開闢了一塊標記區域:Native Method Stack,登記Native方法最終在執行引擎執行的的時候通過JNI(本地方法接口)加載本地方法庫的方法目前該方法使用的越來越少了,
  • jvm面試系列一:java內存模型你掌握了多少?
    今天我們就來聊一聊Java內存模型,面試中面試官會通過考察你對jvm的理解更深入得了解你的水平。
  • JVM內存分析,程式設計師進階的必經之路
    二、JVM內存結構我們看oracle最新的官方文檔,最權威的便是這個官方文檔,畢竟技術是不斷更新的:JVM內存主要分為這五大塊:程序計數器(The pc Register)也就是.class文件便是存儲在這個內存區域。說白了就是類裡面的數據,都是存在這個方法區裡面的。類中有什麼?成員變量,成員方法等等,其中方法和變量還分靜態和非靜態,這些都是存儲在方法區裡面的。
  • 想理解JVM看了這篇文章,就知道了!
    2|0JVM介紹2|1什麼是JVM作為java工程師,對於jvm肯定不陌生。JVM是Java Virtual Machine的縮寫,通俗來說也就是運行java代碼的容器。當項目啟動時,會根據jvm相關配置參數,在計算機的內存中開啟一片空間用於運行JVM。
  • JVM、GC 大串講,面試夠用了
    java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,任何一個確定的時刻,一個處理器都只執行一條線程中的指令。因此,為了線程切換後能恢復到正確的執行位置,每條線程都需要有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲。所以這類內存區域為「線程私有」的內存。
  • JVM 初探:內存分配、GC 原理與垃圾收集器
    對象分配優先在Eden區分配在JVM內存模型一文中, 我們大致了解了VM年輕代堆內存可以劃分為一塊Eden區和兩塊Survivor區.在老年代: 因為對象存活率高、沒有額外空間對它進行分配擔保, 就必須採用「標記—清理」或「標記—整理」算法來進行回收, 不必進行內存複製, 且直接騰出空閒內存.分區收集上面介紹的分代收集算法是將對象的生命周期按長短劃分為兩個部分, 而分區算法則將整個堆空間劃分為連續的不同小區間, 每個小區間獨立使用, 獨立回收.
  • java創建對象的過程詳解(從內存角度分析)
    (從內存角度去分析:重點)重點一、基本知識我們知道,一個對象的創建過程包含兩個過程:初始化和實例化我們在使用一個對象時,JVM首先會檢查相關類型是否已經加載並初始化,如果沒有,則JVM立即進行加載並調用類構造器完成類的初始化。在類初始化過程中或初始化完畢後,根據具體情況才會去對類進行實例化。
  • JVM 垃圾回收算法及回收器詳解
    (點擊上方公眾號,可快速關注)來源:ZIWENXIE,www.ziwenxie.site/2017/07/24/java-jvm-gc
  • JVM性能調優實踐
    ③GC日誌:程序啟動時用 -XX:+PrintGCDetails 和 -Xloggc:/data/jvm/gc.log 可以在程序運行時把gc的詳細過程記錄下來,或者直接配置「-verbose:gc」參數把gc日誌列印到控制臺,通過記錄的gc日誌可以分析每塊內存區域gc的頻率、時間等,從而發現問題,進行有針對性的優化。
  • java垃圾回收以及jvm參數調優概述
    和ParNew區別 5.6  jvm常用監控工具 Java技術體系中所提倡的自動內存管理最終可以歸結為自動化地解決了兩個問題:給對象分配內存以及回收分配給對象的內存。而且這兩個問題針對的內存區域就是Java內存模型中的堆。垃圾回收機制的引入可以有效的防止內存洩露、保證內存的有效使用,也大大解放了Java程式設計師的雙手,使得他們在編寫程序的時候不再需要考慮內存管理。本文主要對java垃圾回收機制以及jvm參數等方面做個綜述,也算是自己做開發這幾年對這方面的一個總結。
  • JVM超神之路:年後跳槽需要的JVM知識點,周末給你整理了一份!!!
    2、對象創建時堆內存分配算法3、對象在內存中的存儲布局4、對象怎麼定位5、判斷對象是否能被回收的算法6、如何判斷對象是否能被回收7、Java堆內存組成部分8、什麼時候拋出StackOverflowError9、Java中會存在內存洩漏嗎,請簡單描述。
  • 13道 常見的JVM 面試題
    3、 Java內存區域(Java內存結構)Java虛擬機在運行程序時把其自動管理的內存劃分為以下幾個區域。這個區域裡的一些數據在JVM啟動的時候創建,在JVM退出的時候銷毀。而其他的數據依賴於每一個線程,在線程創建時創建,在線程退出時銷毀。Java內存區域:
  • 程式設計師每日一題-jvm裡方法和方法區、棧區的二三事
    JAVA虛擬機運行時數據區的邏輯圖好,對照上圖,逐項解釋A:堆區是JVM 所管理的內存中最大的一塊。線程共享,主要是存放對象實例和數組。堆區是jvm裡面最需要深入研究的一塊區域,這裡面涉及內存分配,區域劃分,對象信息,垃圾回收。可以說如果java程式設計師對堆區不熟悉,那麼一定寫不出好的代碼。本文暫時不深入討論,後續會開專題深入講解。B:棧區,也叫虛擬機棧,顧名思義,它是一個棧,先進後出。它是線程創建時跟著創建,生命周期和線程一致,是線程私有的。
  • JVM 面試題解答(40道全)
    5、JVM 有哪些運行時內存區域?/se8/html/jvms-2.html#jvms-2.56、運行時棧幀包含哪些結構?G1特點:JDK 6 開始實驗,JDK 7 商用面向服務端,JDK 9 取代 Parallel Scavenge + Parallel Old結合標記-整理、標記-複製算法首創局部內存回收設計思路基於 Region 內存布局,採用不同策略實現分代不再使用固定大小、固定數量的堆內存分代區域劃分
  • 大型企業JVM性能調優實戰Java垃圾收集器及gcroot
    在我們的java運行時內存當中,程序計數器、Java虛擬機棧、本地方法棧 3個區域都是隨線程生而生,隨線程滅而滅,因此這個區域的內存分配和回收都具備了確定性,所以在這幾個區域不需要太多的考慮垃圾回收問題,因為方法結束了,內存自然就回收了。
  • 淺析JVM內存模型:虛擬機如何實現多線程而導致的並發問題
    一般CPU都會從內存取數據到 寄存器,然後進行處理,但由於內存的處理速度遠遠低於CPU,導致CPU在處理指令時往往花費很多時間在等待內 存做準備工作,於是在寄存器和主內存間添加了CPU緩存,CPU緩存比較小,但訪問速度比主內存快得多,用它來 作為內存與處理器之間的緩衝:將運算需要使用到的數據複製到緩存中,讓運算能快速進行,當運算結束後再從緩 存同步到內存之中,這樣處理器就不用等待緩慢的內存讀寫了