java中的分代垃圾回收策略

什麼是分代垃圾回收策略? java

根據對象的生命週期的長短把對象分紅不一樣的種類(年輕代,年老代和持久代)並分別進行內存回收,就是分代垃圾回收!值得注意的是,這種劃分對象的手段並非自動進行的,而是伴隨着回收過濾進行的,也就是說年輕代與年老代之間的轉換是伴隨着對象回收的,只有通過了回收的洗禮後一些對象纔會被選中成爲年老代,而另一些不幸的對象則早早地就被系統取走了小命。 算法

爲何要運用分代垃圾回收策略?在java程序運行的過程當中,會產生大量的對象,因每一個對象所能承擔的職責不一樣所具備的功能不一樣因此也有着不同的生命週期,有的對象生命週期較長,好比Http請求中的Session對象,線程,Socket鏈接等;有的對象生命週期較短,好比String對象,因爲其不變類的特性,有的在使用一次後便可回收。試想,在不進行對象存活時間區分的狀況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,並且對於存活時間較長的對象進行的掃描工做等都是徒勞。所以就須要引入分治的思想,所謂分治的思想就是因地制宜,將對象進行代的劃分,把不一樣生命週期的對象放在不一樣的代上使用不一樣的垃圾回收方式。 spa

如何劃分?將對象按其生命週期的不一樣劃分紅:年輕代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是類信息,因此與java對象的回收關係不大,與回收息息相關的是年輕代和年老代。 線程

年輕代:年輕代又進一步能夠劃分爲一個伊甸園(Eden)和兩個存活區(Survivor space)伊甸園是進行內存分配的地方,是一塊連續的空閒內存區域,在裏面進行內存分配速度很是快,由於不須要進行可用內存塊的查找。新對象是老是在伊甸園中生成,只有經受住了必定的考驗後才能後順利地進入到存活區中,這種考驗是什麼在後面會講到。把存活區劃分爲兩塊,其實也是爲了知足垃圾回收的須要,由於在年輕代中經歷了「回收大劫」未必就可以進入到年老代中。系統老是把對象放在伊甸園和一個存活區(任意的一個),在垃圾回收時,根據其存活時間被複制到另外一個存活區或者年老代中,則以前的存活區和伊甸園中剩下的都是須要被回收的對象,只要對這兩個區域進行清除便可,兩個存活區是交替使用,循環往復,在下一次垃圾回收時,以前被清除的存活區又用來放置存活下來的對象了。通常來講,年輕代區域較小,並且大部分對象是須要進行清除的。 對象

年老代:在年輕代中經歷了N次回收後仍然沒有被清除的對象,就會被放到年老代中,能夠說他們都是久經沙場而不亡的一代,都是生命週期較長的對象。對於年老代和永久代,就不能再採用像年輕代中那樣搬移騰挪的回收算法,由於那些對於這些回收戰場上的老兵來講是小兒科,而是採用一種稱爲「標記-清除-壓縮(Mark-Sweep-Compact)」的算法。標記的過程是找出當前還存活的對象,並進行標記;清除則是遍歷整個年老區,找到已標記的對象並進行清除;而壓縮則是把存活的對象移動到整個內存區的一端,使得另外一端是一塊連續的空間,方便進行內存分配和複製。 生命週期

持久代:用於存放靜態文件,好比java類、方法等。持久代對垃圾回收沒有顯著的影響。 內存

何時進行回收?因爲對象進行了了分代處理,因此垃圾回收區域和時間也不同。回收(Gabage Colection )的類型有兩種:Scavenge GC和Full GC。 io


  1. Scavenge GC:當新對象生成,但在Eden申請空間失敗時就會觸發Scavenge GC,對Enden去進行GC,清除掉非存活的對象,而且把存活的對象移動到Survivor區中的其中一個區中。前面的提到考驗就是Scavenge GC,也就是說對象通過了Scavenge GC纔可以進入到存活區中。這種形式的GC只會在年輕代中進行,由於大部分對象都是從Eden區開始的,同時Eden區不會分配得太大,因此對Eden區的GC會很是地頻繁。
  2. Full GC:對整個對進行整理,包括了年輕代、年老代和持久代。Full GC要對整個塊進行回收,因此要比Scavenge GC慢得多,所以應該儘量減小Full GC的次數。在對JVM調優的過程當中,很大一部分工做就是對Full GC的調節,以下緣由可能觸發它的執行:
  • 年老代(Tenured)被寫滿
  • 持久代(Permanent)被寫滿
  • System.gc()被顯式調用
  • 自上一次GC以後Heap的各域分配策略動態變化
相關文章
相關標籤/搜索