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

1、快速掃盲

1. JVM是什麼

  JVM是Java Virtual Machine的縮寫,即我們常常提到的Java虛擬機。虛擬機是一種抽象化的計算機,有着本身完善的硬件架構,如處理器、堆棧等,具體有什麼我們不作了解。目前咱們只須要知道想要運行Java文件,必須先經過一個叫javac的編譯器,將代碼編譯成class文件,而後經過JVM把class文件解釋成各個平臺能夠識別的機器碼,最終實現跨平臺運行代碼。
image.pngjava

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

  • JDK:全稱爲Java Development Kit,漢語爲java開發工具包,即全部有關java的東西都包含在裏面,好比運行環境JRE、java的核心代碼、JVM等等。
  • JRE:全稱爲Java Runtime Environment,漢語爲java運行環境,即想要運行java文件必須先有java的環境才行,jre就是提供了這麼一個環境。
  • JVM:上面已經提到了JVM,它是java最核心的部分。

簡單用一張圖來理解這三個的關係:
圖一:JDK、JRE、JVM之間的關係linux

3. jvm的組成成分

圖二:JVM的組成圖
  不瞭解jvm的同窗看到這張圖後可能會有點懵逼,不過不要緊,放這張圖只是想讓你瞭解jvm中有三塊內容很是重要,1.java代碼如何執行?2.內存如何管理?3.線程資源如何利用?腦殼裏有個印象便可,帶着問題去學習。文章最下方有配套電子書和視頻的下載地址。windows

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

  想要運行java的源文件,必需要通過javac編譯器編譯成.class文件,也就是字節碼文件。而後經過jvm中的解釋器,解釋成特定機器上的機器碼。每種機器上的解釋器是不同的,咱們常常用的也就是windows和linux系統,這也是爲何java可以跨平臺的緣由。當一個程序從開始運行,虛擬機就開始實例化,多個程序運行就會存在多個虛擬機實例,程序退出或者關閉,虛擬機實例也將隨之消亡,多個虛擬機之間的數據是不共享的。多線程

2、JVM運行時數據區

1. 運行時數據區域組成

  虛擬機在執行java程序時,會將本身管理的內存劃分爲幾個區域,每一個區域都有本身的用途,而且建立時間和銷燬時間也不同。在程序運行時的內存區域主要能夠劃分爲五個,分別是:方法區、堆、虛擬機棧、本地方法棧、程序計數器。能夠用下面的圖來描述:
Java虛擬機運行時數據區域架構

2. Java堆

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

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虛擬機》這本書
視頻及電子書詳見: 點這裏下載
相關文章
相關標籤/搜索