JVM內存結構分析

  對於Java程序員來說,內存是由JVM自動管理的,所以一旦出現內存泄漏或溢出的問題,不瞭解JVM的內存結構和各個內存區域的工作職責,將對解決問題帶來很大的麻煩,本文參照周志明的《深入理解Java虛擬機》,介紹JVM內存結構,比較枯燥,但對知其然,不知所以然的編碼人員來說還是有一定幫助的。

  按照Java虛擬機規範的規定,JVM自動管理的內存將會包括以下幾個運行時數據區域。

JVM內存結構分析
  程序計數器

  程序計數器(Program Counter Register)是JVM中一塊較小的內存區域,保存着當前線程執行的虛擬機字節碼指令的內存地址。Java多線程的實現,其實是通過線程間的輪流切換並分配處理器執行時間的方式來實現的,在任何時刻,處理器都只會執行一個線程中的指令。在多線程場景下,爲了保證線程切換回來後,還能恢復到原先狀態,找到原先執行的指令,所以每個線程都會設立一個程序計數器,並且各個線程之間不會互相影響,程序計數器爲"線程私有"的內存區域。

  如果當前線程正在執行Java方法,則程序計數器保存的是虛擬機字節碼的內存地址,如果正在執行的是Native方法(非Java方法,JVM底層有許多非Java編寫的函數實現),計數器則爲空。程序計數器是唯一一個在Java規範中沒有規定任何OutOfMemory場景的區域。

  虛擬機棧

  虛擬機棧(Java Virtual Machine Stacks)和線程是緊密聯繫的,每創建一個線程時就會對應創建一個Java棧,所以Java棧也是"線程私有"的內存區域,這個棧中又會對應包含多個棧幀,每調用一個方法時就會往棧中創建並壓入一個棧幀,棧幀是用來存儲方法數據和部分過程結果的數據結構,每一個方法從調用到最終返回結果的過程,就對應一個棧幀從入棧到出棧的過程。

  虛擬機棧是一個後入先出的數據結構,線程運行過程中,只有一個棧幀是處於活躍狀態的,被稱爲"當前活動幀棧",當前活動幀棧始終是虛擬機棧的棧頂元素。

  JVM內存結構分析

  本地方法棧

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

  方法區

  方法區(Method Area)是用於存儲類結構信息的地方,包括常量池、靜態變量、構造函數等類型信息,類型信息是由類加載器在類加載時從類文件中提取出來的。

  方法區同樣存在垃圾收集,因爲用戶通過自定義加載器加載的一些類同樣會成爲垃圾,JVM會回收一個未被引用類所佔的空間,以使方法區的空間達到最小。

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

  方法區是線程共享的。

  堆

  堆(heap)是存儲java實例或者對象的地方,是GC的主要區域,同樣是線程共享的內存區域。

  JVM內存結構分析

  JVM內存結構分析

  案例分析二

  JVM內存結構分析

![](http://i2.51cto.com/images/blog/201811/27/69deff49420fd4358a8639ae131bc1e2.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

  上面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常量池位於方法區中,見如下圖示說明

  JVM內存結構分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章