天天看點

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,在它内部通過調用适當的方法進行處理。

二、運作時資料區概覽

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

Java虛拟機在執行Java程式的過程中會把它所管理的記憶體劃分為上圖若幹個不同的資料區域。這些區域都有各自的用途,已經建立和銷毀時間,有的區域随着虛拟機程序的啟動而建立,有些區域則依賴使用者線程的啟動和結束而建立和銷毀。

三、程式計數器(pc寄存器)

介紹:JVM中的程式計數寄存器(Program Counter Register)中,Register的命名源于CPU的寄存器,寄存器存儲指令相關的現場資訊。CPU隻有把資料裝到寄存器才能夠運作。JVM中的PC寄存器是對計算機PC寄存器的一種抽象模拟。

作用:PC寄存器是用來存儲指向下一條指令的位址,也即将将要執行的指令代碼。由執行引擎讀取下一條指令。

  • 它是一塊很小的記憶體空間,幾乎可以忽略不計。也是運作速度最快的存儲區域
  • 在jvm規範中,每個線程都有它自己的程式計數器,是線程私有的,生命周期與線程的生命周期保持一緻
  • 任何時間一個線程都隻有一個方法在執行,也就是所謂的目前方法。程式計數器會存儲目前線程正在執行的java方法的JVM指令位址;或者,如果實在執行native方法,則是未指定值(undefined)。
  • 它是程式控制流的訓示器,分支、循環、跳轉、異常處理、線程恢複等基礎功能都需要依賴這個計數器來完成
  • 位元組碼解釋器工作時就是通過改變這個計數器的值來選取吓一跳需要執行的位元組碼指令
  • 它是唯一一個在java虛拟機規範中沒有規定任何OOM情況的區域
jvm入門及了解(三)——運作時資料區(程式計數器+本地方法棧)

 CPU時間片

  • CPU時間片即CPU配置設定各各個程式的時間,每個線程被配置設定一個時間段。稱作它的時間片。
  • 在宏觀上:我們可以同時打開多個應用程式,每個程式并行不悖,同時運作。
  • 但在微觀上:由于隻有一個CPU,一次隻能處理程式要求的一部分,如何處理公平,一種方法就是引入時間片,每個程式輪流執行。
  • 并行:同一時間多個線程同時執行;
  • 并發:一個核快速切換多個線程,讓它們依次執行,看起來像并行,實際上是并發

四、本地方法棧

  • Java虛拟機棧用于管理Java方法的調用,而本地方法棧用于管理本地方法的調用
  • 本地方法棧,也是線程私有的。
  • 允許被實作成固定或者是可動态拓展的記憶體大小。(在記憶體溢出方面是相同的)
    • 如果線程請求配置設定的棧容量超過本地方法棧允許的最大容量,Java虛拟機将會抛出一個***Error異常。
    • 如果本地方法棧可以動态擴充,并且在嘗試擴充的時候無法申請到足夠的記憶體,或者在建立新的線程時沒有足夠的記憶體去建立對應的本地方法棧,那麼java虛拟機将會抛出一個OutOfMemoryError異常。
  • 本地方法是使用C語言實作的
  • 它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時加載本地方法庫。
  • 當某個線程調用一個本地方法時,它就進入了一個全新的并且不再受虛拟機限制的世界。它和虛拟機擁有同樣的權限
    • 本地方法可以通過本地方法接口來 通路虛拟機内部的運作時資料區
    • 它甚至可以直接使用本地處理器中的寄存器
    • 直接從本地記憶體的堆中配置設定任意數量的記憶體
  • 并不是所有的JVM都支援本地方法。因為Java虛拟機規範并沒有明确要求本地方法棧的使用語言、具體實作方式、資料結構等。如果JVM産品不打算支援native方法,也可以無需實作本地方法棧。
  • 在hotSpot JVM中,直接将本地方法棧和虛拟機棧合二為一。