標籤:jvm 記憶體地區 運行時資料區
JVM全稱是java Virtual Machine(java虛擬機器),JVM屏蔽了與各個電腦平台相關的軟體和硬體差異。
在接下來的日子裡,通過寫部落格的形式學習JVM,讓自己更懂得Java!
本系列文章是對《深入分析javaweb技術內幕》和《深入理解java虛擬機器》的總結,歡迎大家一起吐槽,一起進步。
《JVM解讀》第一篇:JVM體繫結構
《JVM解讀》第二篇:JVM類載入器ClassLoader
人人都知道的java的一大優點就是不需要程式員去顯示的分配記憶體和回收記憶體,這是由於虛擬機器的自動記憶體管理機制幫我們搞定了這一切。下面我們就來看看虛擬機器是如何劃分記憶體的。
我們將java虛擬機器劃分的記憶體地區叫做運行時資料區域。因為只有在JVM啟動後才會出現這些地區,所以叫做運行時資料區域。先來看張經典的圖
程式計數器
程式計數器是一塊較小的記憶體空間,可以看作當前線程所執行的位元組碼的行號指標。由於虛擬機器的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。為了線上程切換後能恢複到正確的位置,每條線程都需要有一個獨立的程式計數器,相互不影響,隔離儲存區 (Isolated Storage),線程私人的。
如果線程正在執行的是一個java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令地址;如果執行的本地方法,這個計數器為空白
此記憶體地區是唯一一個在java虛擬機器規範中沒有規定任何OutOfMemoryError情況的地區
虛擬機器棧
虛擬機器棧也是線程私人的記憶體地區,棧總是和線程關聯在一起的,每當建立一個線程的時候,JVM就會為這個線程建立一個對應的虛擬機器棧,這個棧中又包含多個棧幀,棧幀是與方法對應的,每運行一個方法,就會在這個棧中建立一個棧幀,棧幀中存放一些內部變數如方法內定義的變數,方法的入參,傳回值等資訊。
每當一個方法執行完後,棧幀就會彈出棧幀的元素作為這個方法的傳回值,並清除這個棧幀,java棧的棧頂就是當前執行的活動棧,也是正在執行的方法,PC寄存器裡的地址也執行此。只有這個活動棧的本地變數可以被操作棧使用,當這個棧幀中又調用另外一個方法時,與之對應的一個新的棧幀又被建立,這個新的棧幀又被放到棧頂,變為活動棧幀,當這個棧幀中所有的指令執行完成後,這個棧幀移除棧,剛才的棧幀又稱為活動棧幀,前面的棧幀的傳回值又變為這個棧幀的操作棧中一個運算元。如果沒有傳回值,當前棧幀的操作棧的運算元沒有變化。
堆
堆是儲存java對象的地方,是JVM管理java對象的核心地區,每個儲存在堆中的java對象都是這個對象類的一方副本,它會複製包括繼承自父類的所有非靜態屬性。堆是被所有java線程所共用的,對它的訪問要注意同步問題,方法和屬性都需要保持一致。
方法區
JVM方法區是用於儲存類結構資訊的地方,一個class檔案被解析成jvm能識別的幾個部分,這些不同的部分在這個class被載入到JVM時,會被儲存在不同的資料結構中,其中常量池,域,方法資料,方法體,建構函式,類中的專有方法,執行個體初始化,介面初始化都存在這個地區。
其實方法區也屬於堆區,我們通常稱為java堆中的永久區(Permanent Generation),這個地區被所有線程共用,這個地區一般在程式啟動後的一段時間內就是固定的了,JVM運行一段時間後,需要載入的類通常都已經載入到JVM中了。
方法區的特殊點在於它不像java堆那樣會被頻繁地被GC回收器回收,它儲存的資訊比較穩定。但是它存在於java堆中,依然會被GC回收器管理。
運行時常量池
運行時常量池是方法區的一部分,class檔案中除了有類的版本,欄位,方法等資訊外,還有一項就是常量池,用於存放編譯期產生的各種字面量和符號引用,這部分內容將在類載入後進入方法區的運行時常量池。
本地方法棧
本地方法棧是為JVM運行本地方法準備的空間,作用和java棧類似。
以上就是虛擬機器運行時資料區的分區情況。下面還要簡單介紹下直接記憶體。直接記憶體並不是虛擬機器運行時資料區的一部分,也不是java虛擬機器規範中定義的部分,但是這部分記憶體也被頻繁地使用,同樣會導致OutOfMemoryError異常出現。
在java1.4後新加入了NIO(New Input/Output)類,引入了一種基於通道與緩衝區的I/O方法,可以直接使用本地函數庫直接分配堆外記憶體,然後通過一個儲存在java堆中的DirectByteBuffer對象最晚這塊記憶體的引用進行操作。可以顯著提高效能,因為避免了java堆和Native堆中來回複製資料。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
JVM解讀:Java記憶體地區