什麼是Java垃圾回收器
Java垃圾回收器是Java虛擬機(JVM)的三個重要模組(另外兩個是解釋器和多執行緒機制)之一,為應用程式提供記憶體的自動分配( Memory Allocation)、自動回收(Garbage Collect)功能,這兩個操作都發生在Java堆上(一段記憶體快)。某一個時點,一個物件如果有一個以上的引用(Rreference)指向它,那麼該物件就為活著的(Live),否則死亡(Dead),視為垃圾,可被垃圾回收器回收再利用。垃圾回收操作需要消耗CPU、線程、時間等資源,所以容易理解的是垃圾回收操作不是實時的發生(對象死亡馬上釋放),當內存消耗完或者是達到某一個指標(Threshold,使用內存佔總內存的比列,如0.75)時,觸發垃圾回收操作。有一個物件死亡的例外,java.lang.Thread類型的物件即使沒有引用,只要執行緒還在運行,就不會被回收。
回收的機制
依據統計分析可知,Java(包括一些其它高階語言)裡面大多數物件生命週期都是短暫的,所以把Java記憶體分代管理。分代的目的無非就是為不同世代的記憶體區塊運用不同的管理策略(演算法),從而最大化效能。相對於年老代,通常年輕代小很多,回收的頻率高,速度快。年老代則回收頻率低,耗時。內存在年輕代裡面分配,年輕代裡面的物件經過多個回收週期依然存活的會自動晉升到年老代。
設計選型(Design Choices)
設計選型影響JVM垃圾回收器的實現難度,以及JVM的性能指標,適用於不同的場景。描述的是回收演算法的風格特徵。
單執行緒串列回收 VS 多執行緒並行回收
回收作業本身是否多執行緒處理的問題。單線程回收的優點是簡單,易實現,碎片少,適用於單核心的機器。多執行緒並行回收在多核心機器上面可以充分的利用CPU資源,減少回收的時間,增加生產力,缺點是複雜且可能有部分碎片沒有回收。
回收時暫停應用執行緒 VS 回收和應用並發進行
回收作業時是否暫停應用執行緒的問題。暫停應用執行緒的優點是簡單、準確、清理得比較乾淨、清理的時間也短(CPU資源獨佔),缺點是暫停應用執行緒之後會造成垃圾回收週期內應用的回應時間拉長,即時性非常高的系統比較敏感。回收和應用線程並行處理的優點是應用反應時間比較平穩、缺點是實現難度高、清理頻率高、可能有碎片。
不合併釋放的記憶體片段 VS 合併釋放的記憶體片段 VS 把活著的複製到新的地方
這三個選型描述的是如何管理死亡的記憶體區塊片段。死亡的記憶體片段通常散落在堆的各個地方,如果不加以管理會有兩個問題,內存分配的時候因查找可用的內存而導致速度慢,小的碎片會導致內存的浪費(比如大的數組要求大的連續記憶體片段)。管理有兩種方式,把活著的記憶體挪到記憶體區塊的某一端,記錄可用記憶體的起始位置,或是乾脆把活著的記憶體複製到新的記憶體區域,原來的記憶體區塊整個空出來。
性能指標(Performance Metrics)
①、生產率(Throughput)
一個較長的周期(長的周期才有意義)內,非回收時間佔總時間的比率。度量系統的運作效率。
②、垃圾回收花費(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。絕大多數的物件都在原始區分配,超過一個垃圾回收作業仍然存活的物件放到存活區。
串行回收器(Serial Collector)
單執行緒執行回收操作,回收期間暫停所有應用執行緒的執行,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)。標記階段把所有存活的對象標記出來,清除階段釋放所有死亡的對象,合併階段 把所有活著的對象合併到年老代的前部分,把空閒的片段都留到後面。設計的選型為合併,減少記憶體的碎片。
同時進行垃圾回收器(Parallel Collector)
使用多個執行緒同時進行垃圾回收,多核心環境裡面可以充分的利用CPU資源,減少回收時間,增加JVM生產率,Server模式中的預設回收器。與串行回收器相同,回收期間暫停所有應用執行緒的執行。透過-XX:+UseParallelGC命令列可選項強制指定。
①年輕代的回收演算法(Minor Collection)
使用多個執行緒回收垃圾,每個執行緒的演算法都與串列回收器相同。
②年老代的回收演算法(Full Collection)
年老代依然是單執行緒的,與串列回收器相同。
並行合併收集器(Parallel Compacting Collection)
年輕代和年老代的回收都是用多執行緒處理。透過指令可選項-XX:+UseParallelOldGC指定,–XX:ParallelGCThreads=3還可進一步指定參與並行回收的執行緒數。與串行回收器相同,回收期間暫停所有應用執行緒的執行。與平行回收器相比,年老代的回收時間較短,從而減少了暫停時間間隔(Pause time)。透過–XX:+UseParallelOldGC命令列可選項強制指定。
①年輕代的回收演算法(Minor Collection)
與並行回收器(Parallel Collector)相同
②年老代的回收演算法(Full Collection)
年老代的回收演算法(Full Collection)
年老代。 、統計、合併。這裡用到分的思想,把年老代劃分成很多固定大小的區(region)。 標記階段,把所有存活的物件劃分為N組(應該與回收線程數相同),每一個線程獨立的負責自己那一組,標記存活對象的位置以及所在區(Region)的存活率信息,標記為並行的。統計階段,統計每一個區(Region)的存活率,原則上靠前面的存活率較高,從前到後, 找到值得合併的開始位置(絕大多數對像都存活的區不值得合併),統計階段是串列的(單線程)。合併階段,依據統計階段的信息,多執行緒 並行的把存活的物件從一個區(Region)複製到另外一個區(Region)。
並發標記清除回收器(Concurrent Mark-Sweep Collector)
又稱為低延時收集器(Low-latency Collector),透過各種手段使得應用程式被掛起的時間最短。基本與應用程式並發地執行回收操作,沒有合併和複製操作。透過命令列-XX:+UseConcMarkSweepGC指定,在單核心或雙核心系統裡面還可以指定使用增量式回收模式-XX:+UseConcMarkSweepGC。增量式回收是指把回收作業分成多個片段,執行一個片段之後釋放CPU資源給應用程序,未來的某個時點接著上次的結果繼續回收下去。目的也是減少延時。
①年輕代的回收演算法(Minor Collection)
與平行回收器(Parallel Collector)相同
②年老代的回收演算法(Full Collection)
初始化階段: 暫停應用線程,找出所有存活的對象,耗時比較短,回收器使用單線程。
並發標記階段: 回收器標記操作與應用並發運行,回收器使用單執行緒標記存活物件。
再次標記:並發標記階段由於應用程式也在運行,這個過程中可能新增或修改物件。所以再次暫停應用線程,找出所有修改的對象,使用多線程標記。
並發清理:回收器清理操作與應用並發運行,回收器使用單執行緒清理死亡物件。
Java垃圾回收器的效能評估工具
①–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命令列可選項即可。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持PHP中文網。
更多Java垃圾回收器的方法和原理總結相關文章請關注PHP中文網!