2、JVM 運行

 

1、方法區-Method Area

線程共享,存儲已經被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等等。(HotSpot虛擬機上開發部署人員更願意成爲“永久代”,Permanent Generation)。

 

1.1、類型信息

  • 類型的全限定名
  • 超類的全限定名
  • 直接超接口的全限定名
  • 類型標誌(該類是類類型還是接口類型)
  • 類的訪問描述符(public、private、default、abstract、final、static)

1.2、類型的常量池

(該部分是獨有的,然後運行時,把該部分加載進運行時常量池,當調用時則從符號引用解析爲直接引用,但是有些確定的方法會直接轉換,比如靜態方法,比如構造方法)

存放該類型所用到的常量的有序集合,包括直接常量(如字符串、整數、浮點數的常量)和對其他類型、字段、方法的符號引用。常量池中每一個保存的常量都有一個索引,就像數組中的字段一樣。因爲常量池中保存中所有類型使用到的類型、字段、方法的符號引用,所以它也是動態連接(棧中對應的方法指向這個引用)的主要對象(在動態鏈接中起到核心作用)。

1.3、字段信息(該類聲明的所有字段)

  • 字段修飾符(public、protect、private、default)
  • 字段的類型
  • 字段名稱

1.4、方法信息

方法信息中包含類的所有方法,每個方法包含以下信息:

  • 方法名 
  • 方法的返回類型(包括void) 
  • 方法參數的類型、數目以及順序 
  • 方法修飾符(public,private,protected,static,final,synchronized,native,abstract)

針對非本地方法,還有些附加方法信息需要存儲在方法區內:

  • 方法字節碼 
  • 方法中局部變量區的大小、方法棧幀 
  • 異常表 

1.5、類變量(靜態變量)

指該類所有對象共享的變量,即使沒有任何實例對象時,也可以訪問的類變量。它們與類進行綁定。

1.6、指向類加載器的引用

每一個被JVM加載的類型,都保存這個類加載器的引用,類加載器動態鏈接時會用到。

1.7、指向Class實例的引用

類加載的過程中,虛擬機會創建該類型的Class實例,方法區中必須保存對該對象的引用。通過Class.forName(StringclassName)來查找獲得該實例的引用,然後創建該類的對象。

1.8、方法表

爲了提高訪問效率,JVM可能會對每個裝載的非抽象類,都創建一個數組,數組的每個元素是實例可能調用的方法的直接引用,包括父類中繼承過來的方法。這個表在抽象類或者接口中是沒有的,類似C++虛函數表vtbl。

2、堆-Heap

JVM內存底層結構:

 

  • VM內存劃分爲堆內存和非堆內存,堆內存分爲年輕代(Young Generation)、老年代(Old Generation),非堆內存就一個永久代(Permanent Generation)。
  • 年輕代又分爲Eden和Survivor區。Survivor區由FromSpace和ToSpace組成。Eden區佔大容量,Survivor兩個區佔小容量,默認比例是8:1:1。

堆內存用途:存放的是對象,垃圾收集器就是收集這些對象,然後根據GC算法回收。

非堆內存用途:永久代,也稱爲方法區,存儲程序運行時長期存活的對象,比如類的元數據、方法、常量、屬性等。

2.1、JDK1.8之前

 

一個對象被創建以後首先被放到的Eden內存中,如果存活期超兩個Survivor之後就會被轉移到長時內存中(Old Generation)中。永久內存中存放着對象的方法、變量等元數據信息。如果永久內存不夠,會發生錯誤:java.lang.OutOfMemoryError: PermGen

2.1、JDK1.8之後

把存放元數據中的永久內存從堆內存中移到了本地內存(native memory)中。

 

永久內存就不再佔用堆內存,它可以通過自動增長來避免JDK7以及前期版本中常見的永久內存錯誤(java.lang.OutOfMemoryError: PermGen)。當然JDK8也提供了一個新的設置Matespace內存大小的參數,通過這個參數可以設置Matespace內存大小,這樣我們可以根據自己項目的實際情況,避免過度浪費本地內存,達到有效利用。

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