Java垃圾回收器是Java虛擬機(JVM)的三個重要模塊(另外兩個是解釋器和多線程機制)之一,爲應用程序提供內存的自動分配(Memory Allocation)、自動回收(Garbage Collect)功能,這兩個操做都發生在Java堆上(一段內存快)。某一個時點,一個對象若是有一個以上的引用(Rreference)指向它,那麼該對象就爲活着的(Live),不然死亡(Dead),視爲垃圾,可被垃圾回收器回收再利用。垃圾回收操做須要消耗CPU、線程、時間等資源,因此容易理解的是垃圾回收操做不是實時的發生(對象死亡立刻釋放),當內存消耗完或者是達到某一個指標(Threshold,使用內存佔總內存的比列,好比0.75)時,觸發垃圾回收操做。有一個對象死亡的例外,java.lang.Thread
類型的對象即便沒有引用,只要線程還在運行,就不會被回收。java
依據統計分析可知,Java(包括一些其它高級語言)裏面大多數對象生命週期都是短暫的,因此把Java內存分代管理。分代的目的無非就是爲不一樣代的內存塊運用不一樣的管理策略(算法),從而最大化性能。相對於年老代,一般年輕代要小不少,回收的頻率高,速度快。年老代則回收頻率低,耗時長。內存在年輕代裏面分配,年輕代裏面的對象通過多個回收週期依然存活的會自動晉升到年老代。算法
設計選型影響JVM垃圾回收器的實現難度,以及JVM的性能指標,適用於不一樣的場景。描述的是回收算法的風格特色。數組
回收操做自身是否多線程處理的問題。單線程回收的優勢是簡單,易實現,碎片少,適用於單核的機器。多線程並行回收在多核機器上面能夠充分的利用CPU資源,減小回收的時間,增長生產力,缺點是複雜且可能有部分碎片沒有回收。性能優化
回收操做時是否暫停應用線程的問題。暫停應用線程的優勢是簡單、準確、清理得比較乾淨、清理的時間也短(CPU資源獨佔),缺點是暫停應用線程以後會形成垃圾回收週期內應用的迴應時間拉長,實時性很是高的系統比較敏感。回收和應用線程並行處理的優勢是應用反應時間比較平穩、缺點是實現難度大、清理頻率高、可能有碎片。多線程
這三個選型描述的是如何管理死亡的內存塊片斷。死亡的內存片斷一般散落在堆的各個地方,若是不加以管理會有兩個問題,內存分配的時候因查找可用的內存而致使速度慢,小的碎片會致使內存的浪費(好比大的數組要求大的連續內存片斷)。管理有兩種方式,把活着的內存挪到內存塊的某一端,記錄可用內存的開始位置,或者乾脆把活着的內存複製到一個新的內存區域,原來的內存塊整個空出來。併發
生產率(Throughput)
一個較長的週期(長的週期纔有意義)內,非回收時間佔總時間的比率。度量系統的運行效率。oracle
垃圾回收花費(Garbage Collection overhead)
一個較長的週期內,回收時間佔總時間的比率。與生產率相對應,加起來爲100%。工具
暫停時間間隔(Pause time)
Java虛擬機在回收垃圾的時候,有的算法會暫停全部應用線程的執行,某些系統可能對暫停的時間間隔比較敏感。性能
回收的頻率(Frequency of collection)
平均多久會發生回收操做。優化
內存佔用的大小(Footprint)
如堆的大小。
實時性(Promptness)
自一個對象死亡起,通過多久該對象所佔用內存被回收。
全部的回收器類型都是基於分代技術。Java HotSpot虛擬機包含三代,年輕代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)。
永久代
存儲類、方法以及它們的描述信息。能夠經過-XX:PermSize=64m
和-XX:MaxPermSize=128m
兩個可選項指定初始大小和最大值。一般 咱們不須要調節該參數,默認的永久代大小足夠了,不過若是加載的類很是多,不夠用了,調節最大值便可。
年老代
主要存儲年輕代中通過多個回收週期仍然存活從而升級的對象,固然對於一些大的內存分配,可能也直接分配到永久代(一個極端的例子是年輕代根本就存不下)。
年輕代
絕大多數的內存分配回收動做都發生在年輕代。以下圖所示, 年輕代被劃分爲三個區域,原始區(Eden)和兩個小的存活區(Survivor),兩個存活區按功能分爲From和To。絕大多數的對象都在原始區分配,超過一個垃圾回收操做仍然存活的對象放到存活區。
單線程執行回收操做,回收期間暫停全部應用線程的執行,client模式下的默認回收器,經過-XX:+UseSerialGC
命令行可選項強制指定。
年輕代的回收算法(Minor Collection)
把Eden區的存活對象移到To區,To區裝不下直接移到年老代,把From區的移到To區,To區裝不下直接移到年老代,From區裏面年齡很大的升級到年老代。 回收結束以後,Eden和From區都爲空,此時把From和To的功能互換,From變To,To變From,每一輪迴收以前To都是空的。設計的選型爲複製。
年老代的回收算法(Full Collection)
年老代的回收分爲三個步驟,標記(Mark)、清除(Sweep)、合併(Compact)。標記階段把全部存活的對象標記出來,清除階段釋放全部死亡的對象,合併階段 把全部活着的對象合併到年老代的前部分,把空閒的片斷都留到後面。設計的選型爲合併,減小內存的碎片。
使用多個線程同時進行垃圾回收,多核環境裏面能夠充分的利用CPU資源,減小回收時間,增長JVM生產率,Server模式下的默認回收器。與串行回收器相同,回收期間暫停全部應用線程的執行。經過-XX:+UseParallelGC
命令行可選項強制指定。
年輕代的回收算法(Minor Collection)
使用多個線程回收垃圾,每個線程的算法與串行回收器相同。
年老代的回收算法(Full Collection)
年老代依然是單線程的,與串行回收器相同。
年輕代和年老代的回收都是用多線程處理。經過命令可選項-XX:+UseParallelOldGC
指定,–XX:ParallelGCThreads=3
還可進一步指定參與並行回收的線程數。與串行回收器相同,回收期間暫停全部應用線程的執行。與並行回收器相比,年老代的回收時間更短,從而減小了暫停時間間隔(Pause time)。經過–XX:+UseParallelOldGC
命令行可選項強制指定。
年輕代的回收算法(Minor Collection)
與並行回收器(Parallel Collector)相同
年老代的回收算法(Full Collection)
年老代分爲三個步驟,標記、統計、合併。這裏用到分的思想,把年老代劃分爲不少個固定大小的區(region)。 標記階段,把全部存活的對象劃分爲N組(應該與回收線程數相同),每個線程獨立的負責本身那一組,標記存活對象的位置以及 所在區(Region)的存活率信息,標記爲並行的。統計階段,統計每個區(Region)的存活率,原則上靠前面的存活率較高,從前到後, 找到值得合併的開始位置(絕大多數對象都存活的區不值得合併),統計階段是串行的(單線程)。合併階段,依據統計階段的信息,多線程 並行的把存活的對象從一個區(Region)複製到另一個區(Region)。
又名低延時收集器(Low-latency Collector),經過各類手段使得應用程序被掛起的時間最短。基本與應用程序併發地執行回收操做,沒有合併和複製操做。經過命令行-XX:+UseConcMarkSweepGC
指定,在單核或者雙核系統裏面還能夠指定使用增量式回收模式-XX:+UseConcMarkSweepGC
。增量式回收是指把回收操做分爲多個片斷,執行一個片斷以後釋放CPU資源給應用程序,將來的某個時點接着上次的結果繼續回收下去。目的也是減小延時。
年輕代的回收算法(Minor Collection)
與並行回收器(Parallel Collector)相同
年老代的回收算法(Full Collection)
分爲四個步驟,初始標記(Initial Mark)、併發標記(Concurrent Mark)、再次標記(Remark)、以及併發清理(Concurrent Sweep)。特別注意,沒有合併操做,因此會有碎片。
初始化階段: 暫停應用線程,找出全部存活的對象,耗時比較短,回收器使用單線程。
併發標記階段: 回收器標記操做與應用併發運行,回收器使用單線程標記存活對象。
再次標記:併發標記階段因爲應用程序也在運行,這個過程當中可能新增或者修改對象。因此再次暫停應用線程,找出全部修改的對象,使用多線程標記。
併發清理:回收器清理操做與應用併發運行,回收器使用單線程清理死亡對象。
–XX:+PrintGCDetails
和–XX:+PrintGCTimeStamps
垃圾回收的開始時間,持續時間,每一代的空餘內存等信息。
jmap [options] pid
jamp 2043 查看2043進程裏面已經加載的共享對象。一般DLL文件。
jmap -heap 2043 查看內存堆的配置信息以及使用狀況。
jmap -permstat 2043 查看永久代的加載狀況。
jmap -histo 2043 查看類的加載和內存佔用狀況。
jstat [options] pid
jstat -class 2043 class加載、卸載、內存佔用狀況。
jstat -gc 2043 GC執行狀況。
Java提供自動選擇和自動性能優化功能。在作垃圾回收器調優以前,先列出所關注的性能指標,經過命令行告訴JVM你所關注的性能指標,由JVM自動調優,若是不滿意,能夠指定垃圾回收器。OutOfMemory一般是因爲堆內存不足,調節-Xmx1024m
和-XX:MaxPermSize=128m
命令行可選項便可。