jvm入門及理解(三)——執行時資料區(程式計數器+本地方法棧)

酒客發表於2020-04-16

一、記憶體與執行緒

記憶體:

記憶體是非常重要的系統資源,是硬碟和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中,直接將本地方法棧和虛擬機器棧合二為一。


相關文章