認識JVM的內存分配

當咱們在JVM中運行一段程序代碼,JVM初始運行的時候都會分配好Method Area(方法區)和Heap(堆),而JVM每遇到一個線程,就爲其分配一個Program Counter Register(程序計數器), VM Stack(虛擬機棧)和Native Method Stack (本地方法棧),當線程終止時,三者(虛擬機棧,本地方法棧和程序計數器)所佔用的內存空間也會被釋放掉。java

這也是爲何我把內存區域分爲線程共享和非線程共享的緣由,非線程共享的那三個區域的生命週期與所屬線程相同,而線程共享的區域與JAVA程序運行的生命週期相同,因此這也是系統垃圾回收的場所只發生在線程共享的區域的緣由。數組

graph LR a(申請新內存)-->b(eden區) b--內存充足-->c(在eden直接分配) b--第一次內存不足-->d(首次進行yong gc,YGC) d--Eden內存活的對象複製到s1-->e(Survivor1,s1) b--第二次內存不足-->f(再次進行YCC) f--eden+s1複製到s2清理eden和s1-->ff(Survivor2,s2) f--生存次數超過閾值的對象-->g(老年代) g--老年代空間不足時-->h(進行full gc,FGC)

No.1 程序計數器

程序計數器是一塊較小的內存區域,做用能夠看作是當前線程執行的字節碼的位置指示器。分支、循環、跳轉、異常處理和線程恢復等基礎功能都須要依賴這個計算器來完成。線程

No.2 虛擬機棧

虛擬機棧也叫棧內存,是在線程建立時建立,它的生命期是跟隨線程的生命期,線程結束棧內存也就釋放,對於棧來講不存在垃圾回收問題,只要線程一結束,該棧就釋放了,因此不存在垃圾回收。 它所描述的是java方法執行的內存模型,每一個方法執行的同時建立幀棧(Strack Frame)用於存儲局部變量表(包含了對應的方法參數和局部變量),操做棧(Operand Stack,記錄出棧、入棧的操做),動態連接、方法出口等信息,每一個方法被調用直到執行完畢的過程,對應這幀棧在虛擬機棧的入棧和出棧的過程。指針

2.一、局部變量表

局部變量表存放了編譯期可知的各類: 基本數據類型(boolean、byte、char、short、int、float、long、double) 對象的引用(reference類型,不等同於對象自己,根據不一樣的虛擬機實現,多是一個指向對象起始地址的引用指針,也多是一個表明對象的句柄或者其餘與對象相關的位置) returnAdress類型(指向下一條字節碼指令的地址) 局部變量表所需的內存空間:在編譯期間分配,運行期間不改變(大小固定)。code

2.二、棧幀

棧幀是一個內存區塊,是一個數據集,是一個有關方法(Method)和運行期數據的數據集,當一個方法 A 被調用時就產生了一個棧幀 F1,並被壓入到棧中,A 方法又調用了 B 方法,因而產生棧幀 F2 也被壓入棧,執行完畢後,先彈出 F2棧幀,再彈出 F1 棧幀,遵循「先進後出」原則。對象

No.3 堆

Heap(堆)是JVM的內存數據區。該區域是被全部線程共享的內存區域,在JVM啓動時候建立,專門用來保存對象的實例。 在Heap中分配必定的內存來保存對象實例,實際上也只是保存對象實例的屬性值,屬性的類型和對象自己的類型標記等,並不保存對象的方法(以幀棧的形式保存在Stack中)。而對象實例在Heap中分配好之後,須要在Stack中保存一個4字節的Heap內存地址,用來定位該對象實例在Heap中的位置,便於找到該對象實例。 堆是線程共享的內存區域,在JVM啓動時候建立,專門用來保存對象的實例。 java堆處於物理不連續的內存空間中,只要邏輯上連續便可。 垃圾回收的主要場所。索引

No.4 方法區

方法區存放了:接口

  • 加載類的類定義數據
  • 常量和靜態變量
  • JIT(即時編譯器)編譯後的代碼

方法區也能夠是內存不連續的區域組成的,而且可設置爲固定大小,也能夠設置爲可擴展的 垃圾回收在這個區域會比較少出現,這個區域內存回收的目的主要針對常量池的回收和類的卸載。生命週期

No.5 運行時常量池(Runtime Constant Pool)

方法區內部有一個很是重要的區域,叫作運行時常量池(Runtime Constant Pool,簡稱 RCP)。 在字節碼文件(Class文件)中,除了有類的版本、字段、方法、接口等相關信息描述外,還有常量池(Constant Pool Table)信息,用於存儲編譯器產生的字面量和符號引用。這部份內容在類被加載後,都會存儲到方法區中的RCP。值得注意的是,運行時產生的新常量也能夠被放入常量池中,好比 String 類中的 intern() 方法產生的常量。 常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)和對其餘類型、方法、字段的符號引用.例如:內存

  • 類和接口的全限定名;
  • 字段的名稱和描述符;
  • 方法和名稱和描述符。

池中的數據和數組同樣經過索引訪問。因爲常量池包含了一個類型全部的對其餘類型、方法、字段的符號引用,因此常量池在Java的動態連接中起了核心做用.

No.6 本地方法棧

與VM Strack類似,VM Strack爲JVM提供執行JAVA方法的服務,Native Method Stack則爲JVM提供使用native 方法的服務。

No.7 直接內存區

直接內存區並非JVM 管理的內存區域的一部分,而是其以外的。該區域也會在 Java 開發中使用到,而且存在致使內存溢出的隱患。若是你對 NIO 有所瞭解,可能會知道 NIO 是可使用 Native Methods 來使用直接內存區的。

JVM內存區域能夠分爲線程共享和非線程共享兩部分,線程共享的有堆和方法區非線程共享的有虛擬機棧,本地方法棧和程序計數器

相關文章
相關標籤/搜索