深入理解 Java 虛擬機:Java 虛擬機內存組成概況

前言

剛開始看《深入理解Java虛擬機》,文章主要就當筆記來用了,整理知識點,方便以後複習查看

Java 虛擬機內存劃分

在這裏插入圖片描述

運行時數據區域

執行 Java 程序的過程中,把它所管理的內存劃分爲若干個不同的數據區域。
這些區域都有各自的用途,以及創建和銷燬時間。
有的區域隨着虛擬機進程的啓動而存在。
有些區域則依賴用戶線程的啓動和結束而建立和銷燬。

程序計數器

程序計數器(Program Counter Register)是塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器。
字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

由於 Java 虛擬機多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。因此爲了線程切換後能恢復到正確的執行位置, 每條線程都需要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立儲存,我們稱這類內存區域爲線程私有的內存。

Java 虛擬機棧

Java 虛擬機棧(Java Virtual Machine Stacks)是線程私有的,它的生命週期與線程相同

每個方法在執行的同時都會創建一個棧幀用於儲存局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應一個棧幀在虛擬機棧中入棧到出棧的過程

就是現在講的虛擬機棧,或者說虛擬機棧中的局部變量表部分

局部變量表

局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference 類型,它不等於對象本身,可能是一個指向對象起始地址的引用指針,也可能時指向一個代表對象的句柄或其他對象相關的位置)。

局部變量表所需的內存空間在編譯期間完成分配。

本地方法棧

本地方法棧(Native Method Stack)是爲虛擬機使用 Native Method 方法服務。在JVM規範中,並沒有對本地方法棧的具體實現方法以及數據結構作強制規定,虛擬機可以自由實現它。
也就是說Java的虛擬機,這個就是按照 Java 實現的 Java 棧,其他語言的就按別的語言自己實現。比如 Sun HotSpot 虛擬機就直接把本地方法棧和虛擬機棧合二爲一。

Java 堆

Java 堆(Java Heap)是 Java 虛擬機所管理的內存中最大的一塊,被所有線程共享的一塊內存區域,在虛擬機啓動時創建。絕大多數情況下,實例與數組都在堆上分配。

但是隨着 JIT 編輯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所有的對象都在堆上分配也漸漸變得不那麼“絕對”了。

Java 堆是垃圾收集器管理的主要區域,因此很多時候也被稱爲“GC 堆”(Garbage Collected Heap)。由於現在收集器基本採用分代收集算法,所以 Java 堆還可以細分爲:新生代和老年代;再細緻點的又 Eden 空間、From Survivor 空間、To Survivor 空間等。從內存分配的角度來看,線程共享的 Java 堆中可能劃分出多個線程私有的分配緩衝區(Thread Local Allocation Buffer,TLAB)。不過無論如何劃分,都與存放內容無關,無論哪個區域,存儲都仍然是對象實例,進一步劃分的目的是爲了更好的回收內存,或者更快的分配內存。

方法區

方法區(Method Area)與 Java 堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

方法區也被很多人稱爲永久代
JDK1.7 的 HosSpot 虛擬機中,雖然永久代還存在,但已經逐步“去永久代”,常量池在堆
JDK1.8 的 HosSpot 虛擬機中,無永久代,常量池在元空間(用的是計算機的直接內存,而不是虛擬機管理的內存)

運行時常量池

運行時常量池(Runtime Constant Pool)是方法區的一部分。Class 文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放

直接內存

直接內存(Direct Memory),也被稱爲堆外內存受本機總內存大小及處理器尋址空間的限制

JDK1.4 引入了 NIO(New Input/Output),一種基於通道(Channel)與緩衝區(Buffer)的 I/O 方式,它可以使用 Native 函數庫直接分配堆外內存,然後通過一個存儲在 Java 堆中的 DirectByteBuffer 對象作爲這塊內存的引用進行操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章