Java方法區的理解


  • 方法區邏輯上是屬於堆的一部分,但一些簡單的實現可能不會選擇去進行垃圾收集或者進行壓縮。
  • 但對於HotSpotJVM而言,方法區還有一個別名叫做Non-Heap,目的就是要和堆分開
  • 所以方法區看作是一塊獨立於Java堆的內存空間

基本理解

  • 方法區(Method Area) 與Java堆一樣,是各個線程共享的內存區域.
  • 方法區在JVM啟動的時候被創建,並且它的實際的物理內存空間中和Java堆區一樣都可以是不連續的.
  • 方法區的大小,跟堆空間一樣,可以選擇固定大小或者可拓展.
  • 方法區的大小決定了系統可以保存多少個類,如果系統定義了太多的類,導致方法區溢出,虛擬機同樣會拋出內存溢出錯誤:java.lang.OutOfMemoryError: PermGen space(1.8以前)或者java.lang.OutOfMemoryError: Metaspace(1.8及以后)
    • 加載大量的第三方的Jar包;Tomcat部署的工程過多(30-50個);大量動態的生成反射類
  • 關閉JVM就會釋放這個區域的內存

方法區大小設置

  • 1.8及以后
    • 設置初始值-XX:MetaspaceSize=100m
    • 設置最大值-XX:MaxMetaspaceSize=100m(默認值是-1,表示沒有限制)

方法區內部結構

方法區存儲什么?

方法區 它用於存儲已被虛擬機加載的類型信息,常量,靜態變量,即時編譯器編譯后的代碼緩存

類型信息

對每個加載的類型(class,interface,enum,annotation),JVM必須在方法區中存儲以下類型信息:

  1. 這個類型的完整有效名稱(全名=包名.類名)
  2. 這個類型直接父類的完整有效名
  3. 這個類型的修飾符(public , abstract , final的某個子集)
  4. 這個類型直接接口的一個有序列表

域(Field)信息

  • JVM必須在方法區中保存類型的所有域的相關信息以及域的聲明順序
  • 域的相關信息包括:域名稱,域類型,域修飾符

方法(Method)信息

JVM必須保存所有方法的以下信息,同域信息一樣包括聲明順序

  • 方法名稱
  • 方法的返回類型
  • 方法參數的數量和類型
  • 方法的修飾符
  • 方法的字節碼,操作數棧,局部變量表及大小(abstract和native方法除外)
  • 異常表
    • 每個異常處理的開始位置,結束位置,代碼處理在程序計數器中的偏移地址,被捕獲的異常類的常量池索引

non-final的類變量

  • 靜態變量和類關聯在一起,隨着類的加載而加載,他們成為類數據在邏輯上的一部分
  • 類變量被類的所有實例共享,即使沒有類實例時你也可以訪問它

全局常量:static final

被聲明為final的類變量的處理方法則不同,每個全局常量在編譯的時候就會被分配

常量池與運行時常量池

常量池:

  • 一個有效的字節碼文件中除了包含類的版本信息,字段,方法以及接口等描述信息外,還包含一項信息那就是常量池表,包括各種字面量和對類型,域和方法的符號引用

簡單來說,常量池可以看作是一張表,虛擬機指令根據這張常量表找到要執行的類名,方法名,參數類型,字面量等類型

運行時常量池:

  • 運行時常量池是方法區的一部分
  • 常量池表是class文件的一部分,用於存放編譯期生成的各種字面量與符號引用,這部分內容將在類加載后放到方法區的運行時常量池中.
  • 在加載類和接口到虛擬機后,就會創建對應的運行時常量池
  • JVM為每個已加載的類型都維護一個常量池.池中的數據像數組項一樣,是通過索引訪問
  • 運行時常量池相對於Class文件常量池的另一重要特征是:具備動態性

方法區在jdk678的演變過程

jdk6:

方法區是個概念,具體實現是通過永久代來實現

jdk7:

將靜態變量和StringTable放到了堆空間中

jdk8:

方法區的實現由元空間實現,存儲在本地內存上,不在占用虛擬機內存.

為什么要用元空間替換永久代?

  1. 為永久代設置空間大小很難確定

    在某些場景下,如果動態加載類過多,容易產生Perm區的OOM.比如某個實際Web工程中,因為功能點比較多,在運行過程中,要不斷動態加載很多類,經常出現致命錯誤

  2. 對永久代進行調優很困難

為什么要將StringTable調整到堆空間中?

jdk7中將StringTable放到了堆空間中,因為永久代的回收效率很低,在full gc的時候才會觸發.而full gc是老年代的空間不足,永久代不足時才會觸發.

這就導致了StringTable回收效率不高.而我們開發中會有大量的字符串被創建,回收效率低,導致永久代內存不足,放到堆里,能及時回收內存


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM