《深刻理解Java虛擬機》--Java內存區域

運行時數據區域: 

       Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域。         以下圖所示:算法


各區域功能:

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

  • 是一塊較小的內存空間,它能夠看做是當前線程所執行的字節碼的行號指示器。字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需 要依賴這個計數器來完成。
  • 因爲Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式來實現的, 在任何一個肯定的時刻,一個處理器(對於多核處理器來講是一個內核)都只會執行一條線程中的指令。所以,爲了線程切換後能恢復到正確的執行位置,每條線程都須要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,咱們稱這類內存區域爲「線程私有」的內存。
  • 若是線程正在執行的是一個Java方法, 這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是Native方法,這個計數器值則爲空(Undefined)。此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域

2.Java虛擬機棧(Java Virtual Machine Stacks)

  • 虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行的同時都會建立一個棧幀(Stack Frame)用於存儲局部變量表、操做數棧、動態連接、方法出口 等信息。每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。
  • 局部變量表存放了編譯期可知的各類基本數據類型(boolean、byte、char、short、int、 float、long、double)、對象引用(reference類型,它不等同於對象自己,多是一個指向對象起始地址的引用指針,也多是指向一個表明對象的句柄或其餘與此對象相關的位置)和returnAddress類型(指向了一條字節碼指令的地址)。
  • 基本數據類型中64位長度的long和double類型的數據會佔用2個局部變量空間(Slot),其他的數據 類型只佔用1個。局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法須要在幀中分配多大的局部變量空間是徹底肯定的,在方法運行期間不會改變局部變量表的大小。

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

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

4.Java堆(Java Heap)

  • 對於大多數應用來講,Java堆是Java虛擬機所管理的內存中最大的一塊。Java堆是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。
  • Java堆是垃圾收集器管理的主要區域,所以不少時候也被稱作"GC堆"(Garbage Collected Heap),若是從內存回收的角度看,因爲如今收集器基本都是採用的分代收集算法, 因此Java堆中還能夠細分爲:新生代和老年代;在細緻一點的有Eden空間, From Survivor空間,To Survivor空間等。不過,不管如何劃分,都與存放內容無關,不管哪一個區域,存儲的都仍然是對象實例,進一步劃分的目的是爲了更好的回收內存,或者更快的分配內存。
  • 根據Java虛擬機規範的規定,Java堆上能夠處於物理上不連續的內存空間中,只要邏輯上是連續的便可,就像咱們的磁盤空間同樣。在實現時,既能夠實現成固定大小的,也能夠是可拓展的,不過當前主流的虛擬機都是按照可拓展來實現的( 經過-Xms 初始化堆,-Xmx 最大堆空間),若是在堆中沒有內存完成實例分配, 而且堆也沒法在拓展時,將會拋OutOfMemoryError異常。

5.方法區(Method Area)

  • 與Java堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,可是它卻有一個別名叫作Non-Heap(非堆),目的應該是與Java堆區分開來。
  • 運行時常量池(Runtime Constant Pool)是方法區的一部分,用於存放編譯期生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常量池中存放。運行時常量池相對於Class文件常量池的另一個重要特徵是具有動態性,Java語言並不要求常量必定只有編譯期才能產生,也就是並不是預置入Class文件中常量池的內容才能進入方 法區運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發人員利用得比較 多的即是String類的intern()方法。

6.直接內存(Direct Memory)

並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用,並且也可能致使OutOfMemoryError異常出現。顯然,本機直接內存的分配不會受到Java堆大小的限制,可是,既然是內存,則確定仍是會受到本機總內存的大小及處理器尋址空間的限制。服務器管理員配置虛擬機參數時,通常會根據實際內存-Xmx等參數信息,但常常會忽略到直接內存,使得各個內存區域的總和大於物理內存限制(包括物理上的和操做系統級的限制),從而致使動態擴展時出現OutOfMemoryError異常。
多線程

相關文章
相關標籤/搜索