天天看點

JVM系列十五(對象配置設定注意項).

減少配置設定率

這個幾乎不用解釋,減少了記憶體的使用量,自然就減少 GC 回收時的壓力,同時降低了記憶體碎片與 CPU 的使用量。在設計對象時,應仔細檢查并問自己:

  • 我真的需要這個對象嗎?
  • 這個字段是我需要的嗎?
  • 我能減少數組的尺寸嗎?
  • 這些對象,是否隻有在極少數情況下,或者隻有初始化的時候才用到?
  • 我是否配置設定了大量記憶體,但實際隻使用其中很小的一部分?
  • 我可以從其它地方拿到相關資料?

縮短對象的生命周期

對于垃圾回收的高性能程式設計有一個基本規則,事實上也是代碼設計的指導規則。

要收集的對象要麼在新生代,要麼不存在。

Collect objects in gen 0 or not at all.

盡量讓一個對象擁有極短的生命周期,在 Minor GC 的時候就能立即被回收了;或者就應該讓對象快速晉升到老年代,永遠保持對長生命周期對象的引用,通常,這也意味着對象可重複使用,尤其在大對象堆中的對象。

一個對象的作用範圍越短,在下一個 GC 出現時,它被晉升到老年代的機會就越小。

是以,要確定對象盡可能早的退出作用域,對于局部變量,可以在最後一次使用後,甚至在方法結束前将其生命周期結束。你可一個用 {} 将代碼包括起來,這不會對你的運作産生影響,但編譯器會認為在這個範圍的對象已經完成了它的生命周期,不再被使用了。如果需要調用對象的方法,盡量減少第一次和最後一次的時間間隔,以便 GC 盡早的回收對象。

如果對象關聯(引用)了一些會長時間保持的對象,則需要解除它們的引用關系。你可能會是以有更多的空值檢查(null判斷),這可能會讓代碼變得更複雜。

降低對象層次的深度/減少對象之間的引用

JVM 是通過 可達性分析算法 來判斷對象是否存活的,如果對象的層次很深,或者大量的引用了其他對象,JVM 在判斷存活的時候就會花很多時間在周遊對象上,這是 GC 造成長時間的一個原因。

另外一個問題是,如果無法輕松的确定對象有多少引用關系,那麼就無法準确的預測對象的生命周期。減少這種複雜度是相當有必要的,它不但可以讓代碼更健壯,同時也友善調試以及獲得更好的性能。

另外,還要注意不同代對象之間的引用也會導緻 GC 的效率低下,特别是舊對象對新對象的引用。例如,如果老年代對象在新生代對象裡有引用關系,那麼每次發生新生代的 GC 時,也需要掃描部分老年代對象,看看他們是否仍然保持到新生代對象的引用上。雖然這不是一次完整的 GC,但它仍然是不要的工作,應該盡量避免這種情況。

避免大對象

JVM 對于大對象的處理邏輯是直接在老年代進行配置設定,這樣做的目的是避免在 Eden 區和及兩個 Survivor 區之間發生大量的記憶體複制。

一般我們代碼中常見的大對象是指那種很長的字元串以及數組,寫程式的時候應當避免,經常出現大對象容易導緻記憶體還有不少空間時就提前觸發垃圾收集以擷取足夠的記憶體空間來“安置”它們。