雜記-幾個JVM(針對HotSpot)的容易忽視的問題

前言

分享幾個JVM的容易忽視的問題,但願對你們有所幫助緩存

哪些區域會出現OOM?

Java堆溢出

  • 咱們知道,JVM參數配置中-Xms表示JVM啓動時分配的內存、-Xmx表示JVM運行過程當中最大可用內存。
  • 因而可知,隨着對象實例增多,超過最大堆分配內存的限制,就會出現OOM。

棧溢出

  • 棧內存容量參數由-Xss決定,而棧內存取決於棧幀數量,即棧深度,以及每一個棧幀的大小
  • 虛擬機棧常見的2種異常分爲OOM以及StackOverflowError,那麼,取決於什麼狀況,會拋相應的異常呢?

取決於棧內存是否支持擴展,HotSpot虛擬機不支持擴展jvm

  • 因爲HotSpot虛擬機不支持擴展,所以OOM的發生狀況:建立線程時就由於沒法得到足夠內存而出現OOM,建立線程時內存不足,偏偏緣由多是每一個線程的棧分配內存設置過大,在操做系統內存使用狀態的影響下發生。
  • 例如,遞歸調用致使棧深度過大、定義大量本地變量增長棧幀中本地變量表長度,超過了-Xss所決定的棧內存容量,就會拋出StackOverflowError

方法區和運行時常量池溢出

[小插曲]方法區和常量池的關係?

  • 運行時常量池是方法區的一部分
  • 方法區存儲已被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯後的代碼緩存等。
  • 運行時常量池:常量池表,用於存放編譯期生成的各類字面量與符號引用。(運行時也能夠將新的常量放入池中,例如String::intern()

[小插曲]方法區 == 永久代?

  • 能夠說,HotSpot虛擬機使用永久代來實現方法區,這二者不等價。
  • JDK 7的HotSpot,把本來放在永久代的字符串常量池String::intern()、靜態變量等移出到堆內存;JDK8徹底放棄永久代,改用本地內存的元空間(類型信息也移到了元空間)。

迴歸正題

  • 所以,若是使用String::intern()來製造方法區和常量池的OOM

一、JDK6或更早:字符串常量池大小增加,致使永久代的內存大小超過-XX:MaxPermSize規定的大小,致使出現PermGen space出現OOM。 二、JDK7開始,字符串常量池移入Java堆中,使用String::intern()報出OOM也是Java heap spacexss

CGLib產生大量的類填充方法區,製造OOM

  • 一、JDK7出現PermGen space出現OOM
  • 二、JDK8出現Java heap space

GC Roots指什麼?

  • 虛擬機棧中引用的對象,各個線程被調用的方法中使用到的參數、局部變量、臨時變量。
  • 方法區類靜態屬性引用的對象。
  • 方法區常量引用的對象,例如字符串常量池的引用。
  • Java虛擬機內部的引用,Class對象、異常對象、系統類加載器。
  • 同步鎖持有的對象(Synchronized)。

參考