jvm入門及理解(三)——運行時數據區(程式計數器+本地方法棧)
一、記憶體與執行緒
記憶體:
記憶體是非常重要的系統資源,是硬碟和cpu的中間倉庫及橋樑,承載著作業系統和應用程式的實時運行。JVM記憶體布局規定了JAVA在運行過程中記憶體申請、分配、管理的策略,保證了JVM的高效穩定運行。不同的jvm對於記憶體的劃分方式和管理機制存在著部分差異(對於Hotspot主要指方法區)
java虛擬機定了了若干種程式運行期間會使用到的運行時數據區,其中有一些會隨著虛擬機啟動而創建,隨著虛擬機退出而銷毀。另外一些則是與執行緒一一對應的,這些與執行緒對應的數據區域會隨著執行緒開始和結束而創建和銷毀。
如圖,灰色的區域為單獨執行緒私有的,紅色的為多個執行緒共享的,即
- 每個執行緒:獨立包括程式計數器、棧、本地棧
- 執行緒間共享:堆、堆外記憶體(方法區、永久代或元空間、程式碼快取)
一般來說,jvm優化95%是優化堆區,5%優化的是方法區。
執行緒:
- 執行緒是一個程式里的運行單元,JVM允許一個程式有多個執行緒並行的執行;
- 在HotSpot JVM,每個執行緒都與作業系統的本地執行緒直接映射。
- 當一個java執行緒準備好執行以後,此時一個作業系統的本地執行緒也同時創建。java執行緒執行終止後。本地執行緒也會回收。
- 作業系統負責所有執行緒的安排調度到任何一個可用的CPU上。一旦本地執行緒初始化成功,它就會調用java執行緒中的run()方法.
查看jvm執行緒的方法:
使用jconsole
HotSpot JVM後台主要執行緒:
- 虛擬機執行緒:這種執行緒的操作時需要JVM達到安全點才會出現。這些操作必須在不同的執行緒中發生的原因是他們都需要JVM達到安全點,這樣堆才不會變化。這種執行緒的執行包括「stop-the-world」的垃圾收集,執行緒棧收集,執行緒掛起以及偏向鎖撤銷
- 周期任務執行緒:這種執行緒是時間周期事件的提現(比如中斷),他們一般用於周期性操作的調度執行。
- GC執行緒:這種執行緒對於JVM里不同種類的垃圾收集行為提供了支援
- 編譯執行緒:這種執行緒在運行時會降位元組碼編譯成本地程式碼
- 訊號調度執行緒:這種執行緒接收訊號並發送給JVM,在它內部通過調用適當的方法進行處理。
二、運行時數據區概覽
Java虛擬機在執行Java程式的過程中會把它所管理的記憶體劃分為上圖若干個不同的數據區域。這些區域都有各自的用途,已經創建和銷毀時間,有的區域隨著虛擬機進程的啟動而創建,有些區域則依賴用戶執行緒的啟動和結束而創建和銷毀。
三、程式計數器(pc暫存器)
介紹:JVM中的程式計數暫存器(Program Counter Register)中,Register的命名源於CPU的暫存器,暫存器存儲指令相關的現場資訊。CPU只有把數據裝到暫存器才能夠運行。JVM中的PC暫存器是對電腦PC暫存器的一種抽象模擬。
作用:PC暫存器是用來存儲指向下一條指令的地址,也即將將要執行的指令程式碼。由執行引擎讀取下一條指令。
- 它是一塊很小的記憶體空間,幾乎可以忽略不計。也是運行速度最快的存儲區域
- 在jvm規範中,每個執行緒都有它自己的程式計數器,是執行緒私有的,生命周期與執行緒的生命周期保持一致
- 任何時間一個執行緒都只有一個方法在執行,也就是所謂的當前方法。程式計數器會存儲當前執行緒正在執行的java方法的JVM指令地址;或者,如果實在執行native方法,則是未指定值(undefined)。
- 它是程式控制流的指示器,分支、循環、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成
- 位元組碼解釋器工作時就是通過改變這個計數器的值來選取嚇一跳需要執行的位元組碼指令
- 它是唯一一個在java虛擬機規範中沒有規定任何OOM情況的區域
CPU時間片
- CPU時間片即CPU分配各各個程式的時間,每個執行緒被分配一個時間段。稱作它的時間片。
- 在宏觀上:我們可以同時打開多個應用程式,每個程式並行不悖,同時運行。
- 但在微觀上:由於只有一個CPU,一次只能處理程式要求的一部分,如何處理公平,一種方法就是引入時間片,每個程式輪流執行。
- 並行:同一時間多個執行緒同時執行;
- 並發:一個核快速切換多個執行緒,讓它們依次執行,看起來像並行,實際上是並發
四、本地方法棧
- Java虛擬機棧用於管理Java方法的調用,而本地方法棧用於管理本地方法的調用
- 本地方法棧,也是執行緒私有的。
- 允許被實現成固定或者是可動態拓展的記憶體大小。(在記憶體溢出方面是相同的)
- 如果執行緒請求分配的棧容量超過本地方法棧允許的最大容量,Java虛擬機將會拋出一個StackOverFlowError異常。
- 如果本地方法棧可以動態擴展,並且在嘗試擴展的時候無法申請到足夠的記憶體,或者在創建新的執行緒時沒有足夠的記憶體去創建對應的本地方法棧,那麼java虛擬機將會拋出一個OutOfMemoryError異常。
- 本地方法是使用C語言實現的
- 它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時載入本地方法庫。
- 當某個執行緒調用一個本地方法時,它就進入了一個全新的並且不再受虛擬機限制的世界。它和虛擬機擁有同樣的許可權
- 本地方法可以通過本地方法介面來 訪問虛擬機內部的運行時數據區
- 它甚至可以直接使用本地處理器中的暫存器
- 直接從本地記憶體的堆中分配任意數量的記憶體
- 並不是所有的JVM都支援本地方法。因為Java虛擬機規範並沒有明確要求本地方法棧的使用語言、具體實現方式、數據結構等。如果JVM產品不打算支援native方法,也可以無需實現本地方法棧。
- 在hotSpot JVM中,直接將本地方法棧和虛擬機棧合二為一。