JVM運行時內存數據區域:
注意:
一個進程都有一套方法區和堆
一個線程都有一套Java虛擬機棧和程序計數器
一、虛擬機棧:
表示Java方法執行的內存模型,每調用一個方法就會為每個方法生成一個棧幀(Stack Frame),用來存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每個方法被調用和完成的過程,都對應一個棧幀從虛擬機棧上入棧和出棧的過程。虛擬機棧的生命周期和線程是相同的。不同的線程使用不同的棧
不過我們這里要說的棧還不是虛擬機棧,而是虛擬機棧里,一個棧幀的操作數棧。因為,我這里只是演示一個方法而已,這一個方法其實就是一個棧幀。
一個棧幀主要由四部分組成:
- 局部變量表
- 操作棧(也叫操作數棧)
- 動態連接
- 返回地址信息
二、程序計數器
2.1 簡述
程序計數器(Program Counter Register)是一塊較小的內存空間,它的作用可以看做是當前線程所執行的字節碼的行號指示器。
2.2 作用
大家都知道,Java程序從源文件創建到程序運行要經過兩大步驟:
- 源文件由編譯器編譯成字節碼(ByteCode)。
- 字節碼由java虛擬機解釋運行。
字節碼解釋器工作時就是通過改變這個 程序計數器 的值來選取下一條需要執行的字節碼指令
當一個線程執行到一半的時候核心切到了第二個線程了,勢必要記錄當前線程要掛起到什么位置上,此信息就是記錄在程序計數器上的,而每一個程序計數器里面的線程執行的信息其實是線程私有的,也就是說A線程是不能得到B線程的程序計數器的。如果一個程序正在執行某一個Java方法,程序計數器記錄的就是正在執行字節碼對應的地址而已。
三、本地方法棧
2.1 簡述
本地方法棧(Native Method Stack)與虛擬機棧所發揮的作用是非常相似的,其 區別 不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務。
四、Java堆
4.1 描述
對于大多數應用來說,Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。
4.2 作用
1、此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。
2、Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC堆”(Garbage Collected Heap)。
4.2 Java堆的組成:
① 如果從內存回收的角度看,由于現在收集器基本都是采用的分代收集算法,所以Java堆中還可以細分為:新生代和老年代;
② 如果從內存分配的角度看,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區(Thread Local Allocation Buffer,TLAB)。
五、方法區
5.1 描述
同 Java 堆一樣,方法區也是全局共享的一塊內存區域。
5.2 作用
1、它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。 類信息和常量池,其中常量池有定義的方法信息、變量信息、常量(字面量和符號引用) **
2、與Java堆不一樣之處在于:方法區并不是垃圾回收的主要區域。**
相對而言,垃圾回收在這個區域是比較少出現的,這個區域的內存回收目標主要是針對常量池的回收和對類型的卸載。 所以會將方法區稱為永久代,但是從JDK1.8開始,已經徹底廢棄了永久代了,使用元空間(Meta Space)代替。
3、當前的商業JVM都有實現方法區的GC,主要是回收兩部分內容:廢棄常量與無用類。
4、類加收需要滿足如下3個條件【條件是極其苛刻的】:
- 1、該類所有的實例都已經被GC,也就是JVM中不存在該Class的任何實例。
- 2、加載該類的ClassLoader已經被GC。(類和類加載器是互相引用的)
- 3、該類對應的java.lang.Class對象沒有在任何地方被引用,如不能在任何地方通過反射訪問該類的方法。
5、在大量使用反射、動態代理、CGLib等字節碼框架、動態生成JSP以及OSGi這類頻繁自定義ClassLoader的場景都需要JVM具備類卸載的支持以保證方法區不會溢出。
5.3 運行時常量池
運行時常量池(Runtime Constant Pool)也是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號引用,這部分將在類加載后進入方法區運行時常量池中存放。
六、直接內存
Direct Memory,它并不是由JVM所管理的一塊區域,而是由系統所管轄的,只不過是JVM向系統申請了這塊內存。