前言
剛開始看《深入理解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
對象作爲這塊內存的引用進行操作。