Java性能優化之垃圾回收機制

[TOC]java


與C/C++相比,java語言不須要程序員直接控制內存回收,java程序的內存分配和回收都是由JRE在後臺自動進行,JRE會負責回收那些再也不使用的內存,這種機制被稱爲垃圾回收機制(Garbage Collection,GC):程序員

主要負責兩件事情

  1. 發現無用的對象
  2. 回收被無用對象佔用的內存空間,使之再次被程序使用(通常是在CPU空閒或者內存不足時)。
事實上,除了釋放沒用對象佔用的內存空間外,垃圾回收也能夠清除內存紀錄碎片(因爲建立對象和垃圾回收器釋放丟棄對象所佔的內存空間)

特色

  1. 垃圾回收機制的工做目標是回收無用對象的內存空間,==這些內存空間都是jvm堆內存(運行時數據區,用以保存類的實例,即對象)裏的內存空間==,不包含其它物力資源,好比數據庫鏈接、磁盤I/O等;
  2. Java語言沒有顯式的提供分配內存和刪除內存的方法,一些開發人員將引用對象設置爲null或者調用System.gc()或者Runtime.getRuntime.gc()來釋放內存(==後兩種方法僅是建議,慎重使用==);
  3. 垃圾回收不可預知,不一樣的jvm採用不一樣的垃圾回收機制和算法,有可能定時發生,有可能CPU空閒時發生,也有可能內存耗盡時發生

分代垃圾回收

image

年輕代(Young Generation)

全部新生成的對象首先都是放在年輕代的。算法

年輕代的目標就是儘量快速的收集掉那些生命週期短的對象數據庫

  • 年輕代分三個區。一個Eden區,兩個Survivor區(通常而言)。大部分對象在Eden區中生成。

當Eden區滿時,還存活的對象將被複制到Survivor區(兩個中的一個)==(YGC,年輕代垃圾回收)==,當這個Survivor區滿時,此區的存活對象將被複制到另一個Survivor區,當這個Survivor區也滿了的時候,從第一個Survivor區複製過來的而且此時還存活的對象,將被複制「年老區(Tenured)」。jvm

須要注意,Survivor的兩個區是對稱的,沒前後關係,因此同一個區中可能同時存在從Eden複製過來 對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。並且,Survivor區總有一個是空的。
同時,根據程序須要,Survivor區是能夠配置爲多個的(多於兩個),這樣能夠增長對象在年輕代中的存在時間,減小被放到年老代的可能。

年老代(Old Generation)

在年輕代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代中。所以,能夠認爲年老代中存放的都是一些生命週期較長的對象。spa

持久代(Permanent Generation)

用於存放靜態文件,現在Java類、方法等。持久代對垃圾回收沒有顯著影響,可是有些應用可能動態生成或者調用一些class,例如Hibernate等,在這種時候須要設置一個比較大的持久代空間來存放這些運行過程當中新增的類。持久代大小經過-XX:MaxPermSize=<N>進行設置。code

什麼狀況下觸發垃圾回收

因爲對象進行了分代處理,所以垃圾回收區域、時間也不同。GC有兩種類型:Minor GC和Full GC。對象

Minor GC

通常狀況下,當新對象生成,而且在Eden申請空間失敗時,就會觸發Minor GC,對Eden區域進行GC,清除非存活對象,而且把尚且存活的對象移動到Survivor區。
而後整理Survivor的兩個區。生命週期

這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。由於大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,因此Eden區的GC會頻繁進行。於是,通常在這裏須要使用速度快、效率高的算法,使Eden去能儘快空閒出來。內存

Full GC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC由於須要對整個對進行回收,因此比Minor GC要慢,所以應該儘量減小Full GC的次數。

在對JVM調優的過程當中,很大一部分工做就是對於Full GC的調節。有以下緣由可能致使Full GC:

  • 年老代(Tenured)被寫滿
  • 持久代(Perm)被寫滿
  • System.gc()被顯示調用
  • 上一次GC以後Heap的各域分配策略動態變化
相關文章
相關標籤/搜索