天天看點

Java虛拟機記憶體配置設定與回收政策簡介記憶體配置設定政策Full GC 的觸發條件

本文介紹Java虛拟機記憶體配置設定與回收政策。以下内容總結來自于《深入了解Java虛拟機:JVM進階特性與最佳實踐(第二版)》

Java虛拟機自動記憶體管理機制包含兩個方面:給對象配置設定記憶體以及回收配置設定給對象的記憶體

記憶體回收與垃圾收集器在很多時候都是影響系統性能、并發能力的主要因素之一,虛拟機之是以提供多種不同的收集器以及提供大量的調節參數,是因為隻有根據實際應用需求、實作方式選擇最優的收集方式才能擷取最高的性能

Minor GC 與 Full GC

  • 新生代GC(Minor GC):指發生在新生代的垃圾收集動作,因為Java對象大多都具備朝生夕滅的特性,是以 Minor GC非常頻繁,一般回收速度也比較快
  • 老年代GC(Major GC / Full GC):指發生在老年代的GC,出現了Major GC,經常會伴随至少一次的Minor GC(但非絕對的,在Parallel Scavenge收集器的收集政策裡就有直接進行Major GC的政策選擇過程)。Major GC的速度一般會比Minor GC慢10倍以上

記憶體配置設定政策

  • 對象優先在 Eden 配置設定

    大多數情況下,對象在新生代 Eden 上配置設定,當 Eden 空間不夠時,發起 Minor GC

  • 大對象直接進入老年代

    大對象是指需要連續記憶體空間的對象,最典型的大對象是那種很長的字元串以及數組。

  • 大對象對虛拟機的記憶體配置設定來說就是一個壞消息(比遇到一個大對象更加壞的消息就是遇到一群“朝生夕滅”的“短命大對象”,寫程式的時候應當避免)
  • 經常出現大對象容易導緻記憶體還有不少空間時就提前觸發垃圾收集以擷取足夠的連續空間來“安置”它們
  • 經常出現大對象會提前觸發垃圾收集以擷取足夠的連續空間配置設定給大對象
  • 虛拟機提供了一個-XX:PretenureSizeThreshold參數,大于此值的對象直接在老年代配置設定,避免在Eden區及兩個Survivor區之間發生大量的記憶體複制
  • 長期存活的對象進入老年代

    為對象定義年齡計數器。對象在Eden出生并經過第一次Minor GC後仍然存活,并且能被Survivor容納的話,将被移動到Survivor空間中,并且對象年齡設為1。對象在Survivor區中每“熬過”一次Minor GC,年齡就增加1歲,當它的年齡增加到一定程度(預設為15歲),就将會被晉升到老年代中

對象晉升老年代的年齡門檻值,可以通過參數-XX:MaxTenuringThreshold設定
  • 動态對象年齡判定

    虛拟機并不是永遠要求對象的年齡必須達到 MaxTenuringThreshold 才能晉升老年代,如果在 Survivor 中相同年齡所有對象大小的總和大于 Survivor 空間的一半,則年齡大于或等于該年齡的對象可以直接進入老年代,無需等到 MaxTenuringThreshold 中要求的年齡

  • 空間配置設定擔保

    在發生 Minor GC 之前,虛拟機先檢查老年代最大可用的連續空間是否大于新生代所有對象總空間,如果條件成立的話,那麼 Minor GC 可以确認是安全的

如果不成立的話虛拟機會檢視 HandlePromotionFailure 的值是否允許擔保失敗。如果允許那麼就會繼續檢查老年代最大可用的連續空間是否大于曆次晉升到老年代對象的平均大小,如果大于,将嘗試着進行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允許冒險,那麼就要進行一次 Full GC。

Full GC 的觸發條件

對于 Minor GC,其觸發條件非常簡單,當 Eden 空間滿時,就将觸發一次 Minor GC。而 Full GC 則相對複雜,有以下條件:

  • 調用 System.gc()

    隻是建議虛拟機執行 Full GC,但是虛拟機不一定真正去執行。不建議使用這種方式,而是讓虛拟機管理記憶體

  • 老年代空間不足

    老年代空間不足的常見場景為前文所講的大對象直接進入老年代、長期存活的對象進入老年代等

為了避免以上原因引起的 Full GC,應當盡量不要建立過大的對象以及數組。除此之外,可以通過 -Xmn 虛拟機參數調大新生代的大小,讓對象盡量在新生代被回收掉,不進入老年代。還可以通過 -XX:MaxTenuringThreshold 調大對象進入老年代的年齡,讓對象在新生代多存活一段時間。
  • 空間配置設定擔保失敗

    使用複制算法的 Minor GC 需要老年代的記憶體空間作擔保,如果擔保失敗會執行一次 Full GC

  • JDK 1.7 及以前的永久代空間不足

    在 JDK 1.7 及以前,HotSpot 虛拟機中的方法區是用永久代實作的,永久代中存放的為一些 Class 的資訊、常量、靜态變量等資料。當系統中要加載的類、反射的類和調用的方法較多時,永久代可能會被占滿,在未配置為采用 CMS GC 的情況下也會執行 Full GC。如果經過 Full GC 仍然回收不了,那麼虛拟機會抛出 java.lang.OutOfMemoryError

  • Concurrent Mode Failure

    執行 CMS GC 的過程中同時有對象要放入老年代,而此時老年代空間不足(可能是 GC 過程中浮動垃圾過多導緻暫時性的空間不足),便會報 Concurrent Mode Failure 錯誤,并觸發 Full GC