Java內存區域JVM內存模型詳解

Java內存區域,JVM內存模型

1. 運行時數據區域

java虛擬機在執行java程序的過程中會把它管理的內存劃分爲若干個不通的數據區域。

Java运行时数据区域

​ (圖片來源於百度,侵權刪)

2. 程序計數器

  • 程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
  • 由於java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的(處理器分片概念)。在任何一個確定的時刻,一個處理器都只會執行一個獨立的程序計數器。所以每個不同的線程會有自己獨立的程序計數器,相互不影響,獨立存儲。我們稱此內存區域爲:線程私有的內存
  • 唯一一個在java虛擬機規範中沒有規定任何oom情況的區域。生命週期與線程相同

3. java虛擬機棧

  • 與程序計數器一樣,java虛擬機棧也是線程私有的,它的生命週期與線程相同。

  • 虛擬機棧描述的是java方法執行的內存莫行:每個方法在執行的同時都會創建一個棧幀用於存儲局部變量、操作數棧、動態鏈接、方法出口等信息。
    在這裏插入圖片描述

  • 局部變量存放了編譯器可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用和返回類型。

  • 其中long和double類型的數據會佔用2個局部變量空間。其餘的類型只佔1個。局部變量表所需要的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改邊局部變量表的大小。

  • 在java虛擬機規範中,對這個區域規定了兩種異常狀況:如果線程請求的棧深度大於當前虛擬機所允許的深度,將拋出StackOverflowError異常。虛擬機棧可動態擴展的情況時無法申請到足夠的內存,就會拋出OOM異常。

4. 本地方法棧

  • 本地方法棧與虛擬機棧發揮的作用是非常相似的,區別是java虛擬機棧執行java方法服務,而本地方法棧使用到的是native方法服務。
  • 與java虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError 和OOM異常。

5. java堆

  • java堆內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存。
  • java虛擬機規範中的描述是:所有的對象實例以及數組都要在堆上分配,但是隨着即時編譯器(JIT)的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換技術將會導致一些微妙的變化發生,所以所有的對象都分配在堆上也漸漸變得沒有那麼絕對了。
  • java堆是垃圾回收器管理的主要區域,也稱爲GC堆。從內存回收的角度來看,由於現在收集器基本都採用分代收集算法,所以java堆中還可以細分爲新生代和老年代、再細緻一點的有eden空間、from survivor空間、to survivor空間等。
  • 如果在堆中沒有內存完成實例分配,並且堆也無法擴展時將會OOM異常
  • 此區域是線程共享區域

6. 方法區

  • 方法區與java堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。也叫non-heap(非堆),目的是和java堆區分開。
  • java1.7之後將字符串常量池移出了永久代,java1.7之前永久代即現在的方法區。
  • 根據java虛擬機規範規定,當方法區無法滿足內存分配的需求時OOM異常

7. 運行時常量池

  • 運行時常量池是方法區的一部分。class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法去的運行時常量池中存放。
  • 既然運行時常量池是方法區的一部分,即處於內存共享區域。當常量池無法再申請到內存時OOM異常
  • 並非預置入Class文件中常量池的內容才能進入方法區運行時常量池。intern()方法用的較多。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章