本文系轉載,原文地址:http://blog.csdn.net/willfcareer/archive/2010/08/23/5833082.aspx
Java虛擬機垃圾收集器分析
1 、活動對象
l 追蹤 root 對象算法: 深度追蹤 root 對象,將 heap 中所有被引用到的 root 做標誌,所有未被標誌的對象視爲非活動對象,所佔用的空間視爲非活動內存。
2 、常用算法
l Copy 算法
1 方法:將內存分爲兩個區域( from space 和 to space )。所有的對象分配內存都分配到 from space 。在清理非活動對象階段,把所有標誌爲活動的對象, copy 到 to space ,之後清楚 from space 空間。然後互換 from sapce 和 to space 的身份。既原先的 from space 變成 to sapce ,原先的 to space 變成 from space 。每次清理,重複上述過程。
2 優點: copy 算法不理會非活動對象, copy 數量僅僅取決爲活動對象的數量。並且在 copy 的同時,整理了 heap 空間,即, to space 的空間使用始終是連續的,內存使用效率得到提高。
3 缺點:劃分 from space 和 to space ,內存的使用率是 1 / 2 。一般在 Young Generation 中使用。
l Compaction 算法
1 方法:在清理非活動對象階段,刪除非活動對象佔用內存,並且把活動對象向 heap 的底部移動,直到所有的活動對象被移到 heap 的一側。
2 優點:無須劃分 from sapce 和 to space ,提高內存的使用率。並且 compaction 後的內存空間也是連續分配的。
3 缺點:該算法相對比較複雜。一般在 Tenured Generation 中使用
1、 內存劃分
l Young Generation
1 生命週期很短的對象,歸爲 young generation 。由於生命週期很短,這部分對象在 gc 的時候,很大部分的對象已經成爲非活動對象。因此針對 young generation 的對象,採用 copy 算法,只需要將少量的存活下來的對象 copy 到 to space 。存活的對象數量越少,那麼 copy 算法的效率越高。
2 young generation 的 gc 稱爲 minor gc 。經過數次 minor gc ,依舊存活的對象,將被移出 young generation ,移到 tenured generation
3 young generation 分爲:
1 eden :每當對象創建的時候,總是被分配在這個區域
2 survivor1 : copy 算法中的 from space
3 survivor2 : copy 算法中的 to sapce (備註:其中 survivor1 和 survivor2 的身份在每次 minor gc 後被互換)
4 minor gc 的時候,會把 eden+survivor1(2) 的對象 copy 到 survivor2(1) 去。
l Tenured Generation
1 生命週期較長的對象,歸入到 tenured generation 。一般是經過多次 minor gc ,還 依舊存活的對象,將移入到 tenured generation 。(當然,在 minor gc 中如果存活的對象的超過 survivor 的容量,放不下的對象會直接移入到 tenured generation )
2 tenured generation 的 gc 稱爲 major gc ,就是通常說的 full gc 。
3 採用 compactiion 算法。由於 tenured generaion 區域比較大,而且通常對象生命週期都比較常, compaction 需要一定時間。所以這部分的 gc 時間比較長。
4 minor gc 可能引發 full gc 。當 eden + from space 的空間大於 tenured generation 區的剩餘空間時,會引發 full gc 。這是悲觀算法,要確保 eden + from space 的對象如果都存活,必須有足夠的 tenured generation 空間存放這些對象。
l Permanet Generation
1 該區域比較穩定,主要用於存放 classloader 信息,比如類信息和 method 信息。
2 對於 spring hibernate 這些需要動態類型支持的框架,這個區域需要足夠的空間。
算法補充:
基本回收算法
- 引用計數(Reference Counting)
比較古老的回收算法。原理是此對象有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只用收集計數爲0的對象。此算法最致命的是無法處理循環引用的問題。 - 標記-清除(Mark-Sweep)
此算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法需要暫停整個應用,同時,會產生內存碎片。 - 複製(Copying)
此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另外 一個區域中。次算法每次只處理正在使用中的對象,因此複製成本比較小,同時複製過去以後還能進行相應的內存整理,不過出現“碎片”問題。當然,此算法的缺 點也是很明顯的,就是需要兩倍內存空間。 - 標記-整理(Mark-Compact)
此算法結合了“標記-清除”和“複製”兩個算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷 整個堆,把清除未標記對象並且把存活對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-清除”的碎片問題,同時也避免了“複製”算法的空間問 題。 - 增量收集(Incremental Collecting)
實施垃圾回收算法,即:在應用進行的同時進行垃圾回收。不知道什麼原因JDK5.0中的收集器沒有使用這種算法的。 - 分代(Generational Collecting)
基於對對象生命週期分析後得出的垃圾回收算法。把對象分爲年青代、年老代、持久代,對不同生命週期的對象使用不同的算法(上述方式中的一個)進行回收。現在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。
二、垃圾回收器
目前的收集器主要有三種:串行收集器、並行收集器、併發收集器 。
- 串行收集器
使用單線程處理所有垃圾回收工作,因爲無需多線程交互,所以效率比較高。但是,也無法使用多處理器的優勢,所以此收集器適合單處理器機器。當然,此收集器也可以用在小數據量(100M 左右)情況下的多處理器機器上。可以使用-XX:+UseSerialGC 打開。 - 並行收集器
- 對年輕代進行並行垃圾回收,因此可以減少垃圾回收時間。一般在多線程多處理器機器上使用。使用-XX:+UseParallelGC .打開。並行收集器在J2SE5.0第六6更新上引入,在Java SE6.0中進行了增強--可以堆年老代進行並行收集。如果年老代不使用併發收集的話,是使用單線程進行垃圾回收 ,因此會制約擴展能力。使用-XX:+UseParallelOldGC 打開。
- 使用-XX:ParallelGCThreads=<N> 設置並行垃圾回收的線程數。此值可以設置與機器處理器數量相等 。
- 此收集器可以進行如下配置:
- 最大垃圾回收暫停: 指定垃圾回收時的最長暫停時間,通過-XX:MaxGCPauseMillis=<N> 指定。<N>爲毫秒.如果指定了此值的話,堆大小和垃圾回收相關參數會進行調整以達到指定值 。設定此值可能會減少應用的吞吐量。
- 吞吐量: 吞吐量爲垃圾回收時間與非垃圾回收時間的比值 ,通過-XX:GCTimeRatio=<N> 來設定,公式爲1/(1+N) 。例如,-XX:GCTimeRatio=19時,表示5%的時間用於垃圾回收。默認情況爲99,即1%的時間用於垃圾回收。
- 併發收集器
可以保證大部分工作都併發進行(應用不停止),垃圾回收只暫停很少的時間,此收集器適合對響應時間要求比較高的中、大規模應用。使用-XX:+UseConcMarkSweepGC 打開。- 併發收集器主要減少年老代的暫停時間,他在應用不停止的情況下使用獨立的垃圾回收線程,跟蹤可達對象。在每個年老代垃圾回收週期 中,在收集初期併發收集器會對整個應用進行簡短的暫停,在收集中還會再暫停一次。第二次暫停會比第一次稍長,在此過程中多個線程同時進行垃圾回收工作。
- 併發收集器使用處理器換來短暫的停頓時間 。在一個N個處理器的系統上,併發收集部分使用K/N 個可用處理器進行回收,一般情況下1<=K<=N/4 。
- 在只有一個處理器的主機上使用併發收集器 ,設置爲incremental mode 模式也可獲得較短的停頓時間。
- 浮動垃圾 :由於在應用運行的同時進行垃圾回收,所以有些垃圾可能在垃圾回收進行完成時產生,這樣就造成了“Floating Garbage”,這些垃圾需要在下次垃圾回收週期時才能回收掉。所以,併發收集器一般需要20% 的預留空間用於這些浮動垃圾。
- Concurrent Mode Failure :併發收集器在應用運行時進行收集,所以需要保證堆在垃圾回收的這段時間有足夠的空間供程序使用,否則,垃圾回收還未完成,堆空間先滿了。這種情況下將會發生“併發模式失敗”,此時整個應用將會暫停,進行垃圾回收。
- 啓動併發收集器 :因爲併發收集在應用運行時進行收集,所以必須保證收集完成之前有足夠的內存空間供程序使用,否則會出現“Concurrent Mode Failure”。通過設置-XX:CMSInitiatingOccupancyFraction=<N> 指定還有多少剩餘堆時開始執行併發收集
- 小結
- 串行處理器:
--適用情況:數據量比較小(100M左右);單處理器下並且對響應時間無要求的應用。
--缺點:只能用於小型應用 - 並行處理器:
--適用情況:“對吞吐量有高要求”,多CPU、對應用響應時間無要求的中、大型應用。舉例:後臺處理、科學計算。
--缺點:應用響應時間可能較長 - 併發處理器:
--適用情況:“對響應時間有高要求”,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發環境。
- 串行處理器: