方法區的垃圾回收


  有些人認為方法區(如Hotspot,虛擬機中的元空間或者永久代)是沒有垃圾收集行為的,其實不然。《Java 虛擬機規范》對方法區的約束是非常寬松的,提到過可以不要求虛擬機在方法區中實現垃圾收集。事實上也確實有未實現或未能完整實現方法區類型卸載的收集器存在(如 JDK11 時期的 2GC 收集器就不支持類卸載)
  一般來說這個區域的回收效果比較難令人滿意,尤其是類型的卸載,條件相當苛刻。但是這部分區域的回收有時又確實是必要的。以前 Sun 公司的 Bug 列表中,曾出現過的若干個嚴重的 Bug 就是由於低版本的 Hotspot 虛擬機對此區域未完全回收而導致內存泄漏

  方法區的垃圾收集主要回收兩部分內容:常量池中廢奔的常量和不再使用的類型

常量池中廢奔的常量

  • 方法區內常量池之中主要存放的兩大類常量:字面量和符號引用
    • 字面量比較接近Java語言層次的常量概念,如文本字符串、被聲明為final的常量值等
    • 符號引用則屬於編譯原理方面的概念,包括下面三類常量:
      • 類和接口的全限定名
      • 字段的名稱和描述符
      • 方法的名稱和描述符
  • HotSpot虛擬機對常量池的回收策略是很明確的,只要常量池中的常量沒有被任何地方引用,就可以被回收
  • 回收廢棄常量與回收Java堆中的對象非常類似

不再使用的類型

  • 判定一個常量是否“廢棄”還是相對簡單,而要判定一個類型是否屬於“不再被使用的類”的條件就比較苛刻了。需要同時滿足下面三個條件
    • 該類所有的實例都已經被回收,也就是Java堆中不存在該類及其任何派生子類的實例
    • 加載該類的類加載器已經被回收,這個條件除非是經過精心設計的可替換類加載器的場景,如OSGi、JSP的重加載等,否則通常是很難達成的
    • 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法
  • Java虛擬機被允許對滿足上述三個條件的無用類進行回收,這里說的僅僅是“被允許”,而並不是和對象一樣,沒有引用了就必然會回收。關於是否要對類型進行回收,HotSpot虛擬機提供了一Xnoclassgc 參數進行控制,還可以使用-verbose:class以及-XX: +TraceClass一Loading、-XX:+TraceClassUnLoading查看類加載和卸載信息
  • 在大量使用反射、動態代理、CGLib等字節碼框架,動態生成JSP以及oSGi這類頻繁自定義類加載器的場景中,通常都需要Java虛擬機具備類型卸載的能力,以保證不會對方法區造成過大的內存壓力

 

 

附:JVM學習目錄


免責聲明!

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



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