天天看點

JVM記憶體結構分析

      對于Java程式員來說,記憶體是由JVM自動管理的,是以一旦出現記憶體洩漏或溢出的問題,不了解JVM的記憶體結構和各個記憶體區域的工作職責,将對解決問題帶來很大的麻煩,本文參照周志明的《深入了解Java虛拟機》,介紹

JVM

記憶體結構,比較枯燥,但對知其然,不知是以然的編碼人員來說還是有一定幫助的。

  按照Java虛拟機規範的規定,JVM自動管理的記憶體将會包括以下幾個運作時資料區域。

  

  程式計數器

  程式計數器(Program Counter Register)是

中一塊較小的記憶體區域,儲存着目前線程執行的虛拟機位元組碼指令的記憶體位址。Java多線程的實作,其實是通過線程間的輪流切換并配置設定處理器執行時間的方式來實作的,在任何時刻,處理器都隻會執行一個線程中的指令。在多線程場景下,為了保證線程切換回來後,還能恢複到原先狀态,找到原先執行的指令,是以每個線程都會設立一個程式計數器,并且各個線程之間不會互相影響,程式計數器為"線程私有"的記憶體區域。

  如果目前線程正在執行Java方法,則程式計數器儲存的是虛拟機位元組碼的記憶體位址,如果正在執行的是Native方法(非Java方法,JVM底層有許多非Java編寫的函數實作),計數器則為空。程式計數器是唯一一個在Java規範中沒有規定任何OutOfMemory場景的區域。

  虛拟機棧

  虛拟機棧(Java Virtual Machine Stacks)和線程是緊密聯系的,每建立一個線程時就會對應建立一個Java棧,是以Java棧也是"線程私有"的記憶體區域,這個棧中又會對應包含多個棧幀,每調用一個方法時就會往棧中建立并壓入一個棧幀,棧幀是用來存儲方法資料和部分過程結果的資料結構,每一個方法從調用到最終傳回結果的過程,就對應一個棧幀從入棧到出棧的過程。

  虛拟機棧是一個後入先出的資料結構,線程運作過程中,隻有一個棧幀是處于活躍狀态的,被稱為"目前活動幀棧",目前活動幀棧始終是虛拟機棧的棧頂元素。

  本地方法棧

  本地方法棧(Native Method Stack)和虛拟機棧的作用相似,不過虛拟機棧是為Java方法服務的,而本地方法棧是為Native方法服務的。

  方法區

  方法區(Method Area)是用于存儲類結構資訊的地方,包括常量池、靜态變量、構造函數等類型資訊,類型資訊是由類加載器在類加載時從類檔案中提取出來的。

  方法區同樣存在垃圾收集,因為使用者通過自定義加載器加載的一些類同樣會成為垃圾,

會回收一個未被引用類所占的空間,以使方法區的空間達到最小。

  方法區中還存在着常量池,常量池包含着一些常量和符号引用(加載類的連接配接階段中的解析過程會将符号引用轉換為直接引用)。

  方法區是線程共享的。

  堆

  堆(heap)是存儲java執行個體或者對象的地方,是GC的主要區域,同樣是線程共享的記憶體區域。

  案例分析一

 

  案例分析二

  上面main方法中運作的程式過程如下:

  (1)使用者建立了一個Student對象,運作時JVM首先會去方法區尋找該對象的類型資訊,沒有則使用類加載器classloader将Student.class位元組碼檔案加載至記憶體中的方法區,并将Student類的類型資訊存放至方法區。

  (2)接着JVM在堆中為新的Student執行個體配置設定記憶體空間,這個執行個體持有着指向方法區的Student類型資訊的引用,引用指的是類型資訊在方法區中的記憶體位址。

  (3)在此運作的JVM程序中,會首先起一個線程跑該使用者程式,而建立線程的同時也建立了一個虛拟機棧,虛拟機棧用來跟蹤線程運作中的一系列方法調用的過程,每調用一個方法就會建立并往棧中壓入一個棧幀,棧幀用來存儲方法的參數,局部變量和運算過程的臨時資料。上面程式中的stu是對Student的引用,就存放于棧中,并持有指向堆中Student執行個體的記憶體位址。

  (4)JVM根據stu引用持有的堆中對象的記憶體位址,定位到堆中的Student執行個體,由于堆中執行個體持有指向方法區的Student類型資訊的引用,進而獲得add()方法的位元組碼資訊,接着執行add()方法包含的指令。

  總結

  1、所有線程共享的記憶體資料區:方法區,堆。而虛拟機棧,本地方法棧和程式計數器都是線程私有的。

  2、存放于棧中的東西如下:

  2.1每個線程包含一個棧區,棧中隻儲存基礎資料類型的對象和自定義對象的引用(不是對象)。對象都存放在堆區中。

  2.2每個棧中的資料(基礎資料類型和對象引用)都是私有的,其他棧不能通路。

  2.3方法的形式參數,方法調用完後從棧空間回收

  2.4引用對象的位址,引用完後,棧空間位址立即被回收,堆空間等待GC

  3、存放于堆中的東西如下:

  3.1存儲的全部是對象,每個對象包含一個與之對應的class資訊

  3.2 Jvm隻有一個堆區(heap)被所有線程共享,堆區中不存放基本類型和對象引用,隻存放對象本身

  4、存放于方法區中的東西如下:

  4.1存放線程所執行的位元組碼指令

  4.2跟堆一樣.被所有線程共享.方法區包含:所有的class和static變量

  4.3常量池位于方法區中,見如下圖示說明