1. 程式人生 > >JVM知識總結-執行時區域劃分

JVM知識總結-執行時區域劃分

區域簡介

JVM執行時區域有些隨著虛擬機器程序的啟動而存在,有些依賴於使用者執行緒的啟動和結束而建立和銷燬,大致分為以下幾類:方法區虛擬機器棧本地方法棧程式計數器,概念圖如下(源於《深入理解JAVA虛擬機器-JVM高階特性》):

程式計數器

  1. 當前執行緒所執行的位元組碼的行號指示器,是一塊各個執行緒私有的記憶體,每個執行緒都有一個獨立的程式計數器;
  2. 如果執行緒執行的是一個JAVA方法,計數器記錄的是虛擬機器位元組碼指令的地址,如果執行的是一個Native方法,計數器值為空(Undefined);
  3. 唯一一個在JVM規範中沒有規定任何OOM情況
    的區域;

虛擬機器棧

  1. 執行緒私有,每個執行緒執行時會建立一個棧楨(Stack Frame),包括區域性變量表、運算元棧、動態連結、方法出口等資訊,一個方法的呼叫過程對應著一個棧楨在虛擬機器棧中的入棧和出棧操作;
  2. 區域性變量表:存放了編譯期可知的各種基本資料型別(byte、short、char、int、long、float、double、boolean),物件引用(reference),returnAddress型別(指向了一條位元組碼指令的地址),64位的long和double佔用兩個Slot(區域性變數空間),其他佔用一個,區域性變量表所需空間在編譯期就確定
  3. JVM規範中這個區域有兩種異常情況,如果執行緒請求的棧深度大於虛擬機器所允許的深度--丟擲StackOverflowError,如果虛擬機器棧可動態擴充套件但擴充套件時申請的記憶體無法滿足--丟擲OutOfMerroyError;

本地方法棧

與虛擬機器棧作用類似,區別在於本地方法棧用於執行Native方法,JVM規範並未對此區域的實現做強制規定,具體的虛擬機器可自由實現,此區域也會丟擲StackOverflowError和OutOfMerroyError;

  1. 所有執行緒共享的區域,幾乎所有的物件例項都在這裡分配記憶體,之所以是幾乎,是因為JIT的優化技術已經使得部分物件例項不必在堆上分配;
  2. 從記憶體分配的角度看,堆中可能劃分出多個執行緒私有的分配緩衝區(Thread Local Allocation Buffer),目的是為了更好回收記憶體或更快的分配記憶體;
  3. 邏輯上連續,物理上可以不連續;
  4. 當堆中沒有足夠的記憶體完成物件例項的分配,且無法再擴充套件,會丟擲OOM;

方法區

  1. 執行緒共享區域,用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、JIT產生的程式碼等資料;
  2. HotSpot將永久代(Permanent Generation)作為方法區的實現,但本質上與方法區並不等價;
  3. 不需要連續的記憶體,可擴充套件,可以選擇不實現垃圾收集(GC只是hotspot在此區域實現的功能),當無法滿足記憶體分配需求時,會丟擲OOM;
  4. 執行時常量池:Class檔案中的常量池--用於存放編譯期生成的各種字面量和符號引用--將在類載入後進入方法區的執行時常量池,除此之外還會把翻譯出來的直接引用也存入,相對於Class檔案常量池的特徵是動態性,執行期間也可以將新的常量放入,如String.intern();

直接記憶體

此區域並不在JVM區域劃分範圍中,但這部分也可能會丟擲OOM,NIO可以通過Native函式庫直接分配堆外記憶體並通過DirectByteBuffer物件對這塊記憶體進行操作,因為避免了資料在Native堆和Java堆之間的複製從而提高效能;