【JVM學習】2.Java虛擬機運行時數據區

來源: 公衆號: 猿人谷面試

這裏咱們先說句題外話,相信你們在面試中常常被問到介紹Java內存模型,我在面試別人時也會常常問這個問題。可是,每每都會令我比較尷尬,我還話音未落,面試者就會「背誦」一段(Java虛擬機是由堆、方法區、虛擬機棧,吧啦吧啦。。。),估計內心還一臉自豪的想幸虧哥提早在網上搜過,早有準備。往往這個時候,我都不忍心打斷,由於「背誦」的真的太順暢了!算法

這也怪不得面試者,首先Java虛擬機方面的知識,對中高級程序猿來講,工做中正面接觸Java虛擬機的東西很少。其次,這個其次咱得好好嘮嘮,網上搜個Java內存模型,度娘推的第一頁大都是介紹Java運行時數據區的,起到了必定的誤導做用,大寫的尷尬。數組

本篇將給各位小夥伴先詳細介紹Java運行時數據區的組成,Java內存模型也是虛擬機裏面的重點,後面會單獨抽出一篇來進行介紹。markdown

1.運行時數據區介紹

程序運行所需的內存空間,有些是不能在編譯期就能肯定,得要在運行期根據實際運行情況動態地在系統中建立。Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域。這些區域都有各自的用途,以及建立和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在,有些區域則依賴用戶線程的啓動和結束而創建和銷燬。數據結構

JVM運行時數據區.png

如圖所示,堆和方法區是全部線程共享的公共區域,堆和方法區所佔的內存空間是由JVM負責管理的,在該區域內的內存分配是由HotSpot的內存管理模塊維護的,而內存的釋放工做則由垃圾收集器自動完成。虛擬機棧、本地方法棧、程序計數器是線程的私有區域,每一個線程都關聯着惟一的棧和程序計數器,並僅能使用屬於本身的那份棧空間和程序計算器來執行程序。函數

2.堆(Heap)

對於大多數應用來講,Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊。堆是可供各個線程共享的運行時內存區域,在虛擬機啓動的時候就被建立。此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。這一點在Java虛擬機規範中的描述就是:全部的對象實例以及數組對象都要在堆上分配。可是隨着JIT編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會致使一些微妙的變化發生,全部的對象都分配在堆上也漸漸變得不是那麼「絕對」了。性能

Java堆的容量能夠是固定的,也能夠隨着程序執行的需求動態擴展,並在不須要過多空間時自動收縮。Java堆能夠處於物理上不連續的內存空間中,只要邏輯上是連續的便可。若是在堆中沒有內存完成實例分配,而且堆也沒法再擴展時,將會拋出OutOfMemoryError異常。優化

Java堆是垃圾收集器管理的主要區域,所以不少時候也被稱作「GC堆」(Garbage Collected Heap)。從內存回收的角度來看,因爲如今收集器基本都採用分代收集算法,Java虛擬機將堆劃分爲新生代和老年代。其中,新生代又被分爲Eden區,以及兩個大小相同的Survivor區(From Survivor,To Survivor)。默認狀況下,Java虛擬機採起的是一種動態分配的策略(JVM參數-XX:+UsePSAdaptiveSurvivorSizePolicy),根據生成對象的速率,以及Survivor區的使用狀況,動態調整Eden區和Survivor區的比例。也能夠經過參數(SurvivorRatio)來調整這個比例,SurvivorRatio這個參數就是新生代中Eden區與Survivor區的容量比值,默認是8,表明Eden:Survivor=8:1。spa

JVM堆分代.png

是否可能有兩個對象共用一段內存的事故?

當調用new指令時,會在Eden區劃出一塊做爲存儲對象的內存。因爲堆空間是線程共享的,所以直接在這裏邊劃空間是須要進行同步的。不然,將有可能出現兩個對象共用一段內存的事故。解決方法就是,Java堆中可能劃出多個線程私有的分配緩衝區TLAB(Thread Local Allocation Buffer,對應的虛擬機參數-XX:+UseTLAB,默認開啓)。線程

具體來講,每一個線程能夠向Java虛擬機申請一段連續內存,好比2048字節,做爲線程私有的TLAB。這個操做須要加鎖,線程須要維護兩個指針(實際上可能更多,但重要也就兩個),一個指向TLAB中空餘內存的起始位置,一個則指向TLAB末尾。接下來的new指令,即可以直接經過指針加法(bump the pointer),也有人叫作指針碰撞來實現,即把指向空餘內存位置的指針加上所請求的字節數。若是加法後空餘內存指針的值仍小於或等於指向末尾的指針,則表明分配成功。不然,TLAB已經沒有足夠的空間來知足本次新建操做。這個時候,便須要當前線程從新申請新的TLAB。

3.方法區(Method Area)

方法區與堆同樣是線程共享的,在虛擬機啓動的時候建立,方法區可視爲堆的一個邏輯部分,可是它卻有一個別名叫作Non-Heap(非堆),目的應該是與Java堆區分開來。

方法區相似於傳統語言編譯後的代碼存儲區域,它存儲每一個類的結構信息,如:

  • 常量池
  • 方法數據
  • 方法和構造函數的字節碼
  • 類、實例、接口初始化時用到的特殊方法

備註:《深刻理解Java虛擬機》裏將方法區概括爲用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

Java虛擬機規範對方法區的限制很是寬鬆,除了和Java堆同樣不須要連續的內存和能夠選擇固定大小或者可擴展外,還能夠選擇不實現垃圾收集。這區域的內存回收目標主要是針對常量池的回收和對類型的卸載。

4.程序計數器(Program Counter Register)

Java虛擬機能夠支持多條線程同時執行,每一條Java虛擬機線程都有本身的程序計數器。在任意時刻,一條Java虛擬機線程只會執行一個方法的代碼,這個正在被線程執行的方法稱爲該線程的當前方法(current methon)。若是這個方法不是native的,那程序計數器保存的就是Java虛擬機正在執行的字節碼指令的地址。若是該方法是native方法,那程序計數器的值爲空(undefined)。程序計數器的容量至少應當保存一個returnAddress類型的數據或者一個與平臺相關的本地指針的值。

程序計數器是一塊較小的內存空間,它能夠看做是當前線程所執行的字節碼的行號指示器。此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。

5.虛擬機棧(VM Stack)

每一條Java虛擬機線程都有本身私有的Java虛擬機棧,它的生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行的同時都會建立一個棧幀(stack frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。

Java虛擬機棧可能發生以下異常狀況:

  • 若是線程請求分配的棧容量超過Java虛擬機棧容許的最大容量,Java虛擬機將會拋出一個StackOverflowError異常。
  • 若是Java虛擬機棧能夠動態擴展,而且在嘗試擴展的時候沒法申請到足夠的內存,或者在建立新的線程時沒有足夠的內存區建立對應的虛擬機棧,那Java虛擬機將會拋出一個OutOfMemoryError異常

6.本地方法棧(Native Method Stack)

本地方法棧與虛擬機棧所發揮的做用是很是類似的,它們之間的區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的native方法服務。

Java虛擬機規範容許本地方法棧實現成固定大小或者根據計算來動態擴展和收縮。若是採用固定大小的本地方法棧,那麼每個線程的本地方法棧容量能夠在建立棧的時候獨立選定。

與虛擬機棧同樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。

7.擴展知識點

7.1 棧上分配和逃逸分析

在棧中分配的基本思路是這樣的:分析局部變量的做用域僅限於方法內部,則JVM直接在棧幀內分配對象空間,避免在堆中分配。這個分析過程稱爲逃逸分析(也有叫逸出分析),而棧幀內分配對象的方式稱爲棧上分配

這樣作的目的是減小新生代的收集次數,間接提升JVM性能。虛擬機是容許堆逃逸分析開關進行配置的,從Sun Java 6u23之後,HotSpot默認開啓逃逸分析。

7.2 棧幀

棧幀是用於支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機運行時數據區中的虛擬機棧的棧元素。棧幀存儲了方法的局部變量表、操做數棧、動態鏈接和方法返回地址等信息每個方法從調用開始至執行完成的過程,都對應着一個棧幀在虛擬機棧裏面從入棧到出棧的過程。

在編譯程序代碼的時候,棧幀中須要多大的局部變量表,多深的操做數棧都已經徹底肯定了,而且寫入到方法表的Code屬性之中。所以一個棧幀須要分配多少內存,不會收到程序運行期變量數據的影響,而僅僅取決於具體的虛擬機實現。

一個線程中的方法調用鏈可能會很長,不少方法都同時處於執行狀態。對於執行引擎來講,在活動線程中,只有位於棧頂的棧幀纔是有效的,稱爲當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱爲當前方法(Current Method)。執行引擎運行的全部字節碼指令都只針對當前棧幀進行操做。棧幀的概念結構以下:棧幀的概念結構.png

8.運行時數據區腦圖

運行時數據區.png

高清、無碼、完整腦圖能夠私信或留言告知哦!!!

相關文章
相關標籤/搜索