垃圾回收(Garbage Collection,GC),就是經過垃圾收集器把內存中沒用的對象清理掉。垃圾回收涉及到內容:算法
判斷對象是否已死:找出哪些對象是已經死掉的,之後不會再用到的。性能優化
判斷對象是否已死的方法:引用計數算法和可達性分析算法。多線程
給每個對象添加一個引用計數器,每當有一個地方引用它時,計數器值加 1;每當有一個地方不在引用它時,計數器值減 1,這樣只要計數器的值不爲 0,就說明還有地方引用它,它就不是無用的對象。併發
這種方法看起來很是簡單,可是目前許多主流的虛擬機都沒有選用這種算法來管理內存,原理就是當某些對象之間互相引用時,沒法判斷出這些對象是否已死。性能
算法的基本思路:經過一系列的稱爲GC Roots
的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到 GC Roots 沒有任何引用鏈相連時,則證實此對象是不可用的。學習
在 Java 語言中,可做爲 GC Roots 的對象包括下面幾種:優化
經常使用的垃圾回收算法有三種:spa
分爲 標記 和 清除 兩個階段,首先標記出全部須要回收的對象,標記完成後統一回收全部被標記的對象。線程
不足之處:3d
爲了解決 "標記-清除" 算法內存碎片化的缺陷而被提出的算法。根據內存容量將內存劃分爲相等大小的兩塊。每次只使用其中一塊,當這一塊內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用過的內存空間一次清理掉。
優勢:效率要高於標記-清除算法,不會產生過多的碎片。在對象存活率較高時要進行較多的複製操做,效率會較低。
缺點:可用內存被壓縮到本來的一半。且存儲對象增多的話,Copying 算法的效率會大大下降。
先對可用的對象進行標記,而後全部被標記的對象都向一端移動,最後直接清理掉端邊界之外的內存。
優勢:自帶整理功能,這樣不會產生大量不連續的內存空間,適合老年代的大對象存儲。
分代收集算法是目前大部分 JVM 所採用的方法,其核心思想就是根據對象存活的不一樣生命週期將內存劃分爲不一樣的域(把堆內存分爲新生代和老年代)。老年代的特色是每次垃圾回收只有少許對象須要被回收,新生代的特色是每次垃圾回收時都有垃圾須要被回收,所以能夠根據不一樣區域選擇不一樣的回收算法。
新生代與複製算法
目前大部分 JVM 的 GC 對於新生代都採用 Copying 算法,由於新生代中每次垃圾回收都會回收大部分對象,即要複製的對象比較少,一般並非按照 1:1 來劃分新生代。通常將新生代劃分爲一塊較大的 Eden 區和兩個較小的 Survivor 區(From Survivor、To Survivor),每次使用 Eden 區和其中一塊 Survivor 區,當進行回收的時候,將該兩塊空間中還存活的對象複製到另一塊 Survivor 空間中。
老年代與標記複製算法
老年代由於每次只會回收少許對象,於是採用 Mark-Compact 算法
如今常見的垃圾收集器有以下幾種:
Serial 收集器是最基本、發展歷史最悠久的收集器。Serial 收集器是一個單線程的收集器,可是這個"單線程"的意義並不只僅說明它只會使用一個 CPU 或一條收集線程去完成垃圾收集工做,更重要的是在它進行垃圾收集時,必須暫停其餘全部的工做線程,直到它收集結束(Stop The World)。
Serial 收集器是虛擬機運行在 Client 模式下的默認新生代收集器。
優勢:簡單而高效,對於限定單個 CPU 的環境來講,Serial 收集器沒有線程交互的開銷,專心作垃圾收集能夠得到最高的單線程收集效率。
適用場景:適合運行在 Client 模式下的虛擬機。
ParNew 收集器是 Serial 收集器的多線程版本,可使用多條線程進行垃圾收集。
ParNew 是運行在 Server 模式下的虛擬機中首選的新生代收集器,只有 ParNew 收集器可以與 CMS 收集器配合工做。
ParNew 默認開啓的收集線程數與 CPU 的數量相同,在 CPU 很是多的環境下,可使用 -XX:ParallelGCThreads
參數來限制垃圾收集的線程數。
Parallel Scavenge 是一個新生代收集器,使用複製算法實現,並行的多線程收集器,吞吐量優先的收集器。
Parallel Scavenge 收集器的目標是 達到一個可控制的吞吐量(Throughput)。
Parallel Scavenge 收集器提供了兩個參數用於精確控制吞吐量,分別是控制最大垃圾收集停頓時間的 -XX:MaxGCPauseMillis
參數以及設置吞吐大小的 -XX:GCTimeRatio
參數。
MaxGCPauseMills:容許的值是一個大於 0 的毫秒數,收集器將盡量地保證內存回收話費的時間不超過設定值。
GCTimeRatio:參數的值是一個大於 0 且小於 100 的證書,就是垃圾收集時間佔總時間的比率,至關因而吞吐量的倒數。
Serial Old 是 Serial 收集器的老年代版本,單線程收集器,使用"標記-整理"算法。
適合 Client 模式下的虛擬機使用。
在 Server 模式下,還有兩大用途:
Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多線程和"標記-整理"算法。從 JDK 1.6 開始提供。 在注重吞吐量以及 CPU 資源敏感的場合,均可以優先考慮 Parallel Scavenge 加 Parallel Old 收集器。
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。CMS 收集器是基於"標記-清除"算法實現的,它的運做過程相對於前面幾種收集器來講更復雜一些,整個過程分爲 4 個步驟:
CMS 是一款優秀的收集器,主要優勢:併發收集、低停頓。可是 CMS 還存在如下 3 個缺點:
G1(Garbage First) 收集器是當今收集器技術發展的最前沿成果之一。
G1 收集器是基於 標記-整理 算法實現的收集器,它不會產生空間碎片,能夠很是精確地控制停頓。
G1 是一款 面向服務端應用 的垃圾收集器。與其餘 GC 收集器相比,G1 具有以下特色:
Stop-The-World
停頓時間,部分其餘收集器本來須要停頓 Java 線程執行的 GC 動做,G1 收集器仍然能夠經過併發的方式讓 Java 程序繼續執行。參數 | 描述 |
---|---|
UseSerialGC | 虛擬機運行在 Client 模式下的默認值,打開此開關後,使用 Serial + Serial Old 的收集器組合進行內存回收 |
UseParNewGC | 使用 ParNew + Serial Old 收集器組合進行內存回收 |
UseConcMarkSweepGC | 使用 ParNew + CMS + Serial Old 的收集器組合進行內存回收。Serial Old 收集器將做爲CMS收集器出現 Concurrent Mode Failure 失敗後的後備收集器使用 |
UseParallelGC | 虛擬機運行在 Server 模式下的默認值,使用 Parallel Scavenge + Serial Old(PS MarkSweep)的收集器組合進行內存回收 |
UseParallelOldGC | 使用 Parallel Scavenge + Parallel Old 的收集器組合進行內存回收 |
SurvivorRatio | 新生代中 Eden 區域與 Survivor 區域的容量比值,默認爲8,表明Eden:From:To=8:1:1 |
PretenureSizeThreshold | 直接晉升到老年代的對象大小,設置這個參數後,大於這個參數的對象將直接在老年代分配 |
MaxTenuringThreshold | 晉升到老年代的年齡。每一個對象在堅持過一次 Minor GC 以後,年齡就加 1,當超過這個參數值時就進入老年代 |
UseAdaptiveSizePolicy | 動態調整 Java 堆中各個區域的大小以及進入老年代的年齡 |
HandlePromotionFailure | 是否容許分配擔保失敗,即老年代的剩餘空間不足以應對新生代的整個 Eden 和 Survivor 區的全部對象都存活的極端狀況 |
ParallelGCThreads | 設置並行 GC 時進行內存回收的線程數 |
GCTimeRatio | GC 時間佔總時間的比率,默認爲99,即容許 1% 的 GC 時間,僅在使用 Parallel Scavenge 收集器時生效。 |
MaxGCPauseMillis | 設置 GC 的最大停頓時間。僅在使用 Parallel Scavenge 收集器時生效 |
CMSInitiationOccupancyFraction | 設置 CMS 收集器在老年代空間誒使用多少後觸發垃圾收集。默認值爲68%,僅在使用 CMS 收集器時生效 |
UseCMSCompactAtFullCollection | 設置 CMS 收集器在完成垃圾收集後是否要進行一次內存碎片整理。僅在使用 CMS 收集器時生效 |
CMSFullGCsBeforeCompaction | 設置 CMS 收集器在進行若干次垃圾收集後再啓動一次內存碎片整理。僅在使用 CMS 收集器時生效 |
-XX:PretenureSizeThreshold
參數,令大於這個設置值的對象直接在老年代中分配。這樣作的目的是避免在 Eden 區及兩個 Survivor 區以前發生大量的內存拷貝。Minor GC:指發生在新生代(包括 Eden 區和 Survivor 區)的垃圾收集動做,由於 Java 對象大多都具有朝生夕滅的特性,因此 Minor GC 很是頻繁,通常回收速度也比較快。
Major GC:指發生在老年代的 GC,出現了 Major GC,常常會伴隨至少一次 Minor GC(但非絕對的,在 Parallel Scavenge 收集器的收集策略裏就有直接進行 Major GC 的策略選擇過程)。Minor GC 的速度通常會比 Minor GC 的速度慢 10 倍以上。
Full GC:針對新生代、老年代、元空間(Metaspace、Java8 以上版本取代 Perm gen)的全局範圍的 GC。Full GC 不等於 Major GC,也不等於 Minor GC + Major GC,發生 Full GC 須要看使用了什麼垃圾收集器組合,才能解釋是什麼樣的垃圾回收。
推薦推薦: