日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jvm垃圾回收之垃圾收集器

發布時間:2023/12/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jvm垃圾回收之垃圾收集器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概念

  • 圖中展示了7種不同分代的收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;
  • 而它們所處區域,則表明其是屬于新生代收集器還是老年代收集器:
  • 新生代收集器:Serial、ParNew、Parallel Scavenge;
  • 老年代收集器:Serial Old、Parallel Old、CMS;
  • 整堆收集器:G1;
  • 兩個收集器間有連線,表明它們可以搭配使用:Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;
  • 其中Serial Old作為CMS出現“Concurrent Mode Failure”失敗的后備預案。
  • 并發和并行收集器:

  • 并行(Parallel):指多條垃圾收集線程并行工作,但此時用戶線程仍然處于等待狀態; 如ParNew、Parallel Scavenge、Parallel Old;
  • 并發(Concurrent):指用戶線程與垃圾收集線程同時執行(但不一定是并行的,可能會交替執行); 用戶程序在繼續運行,而垃圾收集程序線程運行于另一個CPU上;如CMS、G1(也有并行);
  • Minor and Full GC:

  • Minor GC:又稱新生代GC,指發生在新生代的垃圾收集動作;因為Java對象大多是朝生夕滅,所以Minor GC非常頻繁,一般回收速度也比較快;
  • Full GC:又稱Major GC或老年代GC,指發生在老年代的GC;出現Full GC經常會伴隨至少一次的Minor GC(不是絕對,Parallel Sacvenge收集器就可以選擇設置Major GC策略);Major GC速度一般比Minor GC慢10倍以上;
  • GC詳細分類:

  • 針對HotSpot VM的實現,它里面的GC其實準確分類只有兩大類(Partial GC、Full GC)
  • Partial GC:并不收集整個GC堆的模式
  • Young GC:只收集young gen的GC
  • Old GC:只收集old gen的GC。只有CMS的concurrent collection是這個模式Mixed
  • GC:收集整個young gen以及部分old gen的GC。只有G1有這個模式
  • Full GC:收集整個堆,包括young gen、old gen、perm gen(如果存在的話)等所有部分的模式
  • Major GC通常是跟full GC是等價的,收集整個GC堆。

    GC觸發時機:

  • 最簡單的分代式GC策略,按HotSpot VM的serial GC的實現來看,觸發條件是:
  • Young GC:當young gen中的eden區分配滿的時候觸發。注意young GC中有部分存活對象會晉升到old gen, 所以young GC后old gen的占用量通常會有所升高。
  • Full GC:當準備要觸發一次young GC時,如果發現統計數據說之前young GC的平均晉升大小比目前old gen 剩余的空間大,則不會觸發young GC而是轉為觸發full GC(因為HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都會同時收集整個GC堆,包括young gen,所以不需要事先觸發一次單獨的young GC);或者,如果有perm gen的話,要在perm gen分配空間但已經沒有足夠空間時,也要觸發一次full GC;或者System.gc()、heap dump的GC,默認也是觸發full GC。
  • HotSpot VM里其它非并發GC的觸發條件復雜一些,不過大致的原理與上面說的其實一樣。當然也總有例外。Parallel Scavenge(-XX:+UseParallelGC)框架下,默認是在要觸發full GC前先執行一次young GC,并且兩次GC之間能讓應用程序稍微運行一小下,以期降低full GC的暫停時間(因為young GC會盡量清理了young gen的死對象,減少了full GC的工作量)。控制這個行為的VM參數是-XX:+ScavengeBeforeFullGC。
  • 并發GC的觸發條件就不太一樣。以CMS GC為例,它主要是定時去檢查old gen的使用量,當使用量超過了觸發比例就會啟動一次CMS GC,對old gen做并發收集。
  • safepoint(安全點)

  • 什么是安全點:安全點是在程序執行期間的所有GC Root已知并且所有堆對象的內容一致的點。從全局的角度來看,所有線程必須在GC運行之前在安全點阻塞。也就是說當線程運行到安全點時,堆對象狀態是確定一致的,JVM可以安全地進行操作,如GC,偏向鎖解除等。
  • 安全點位置:
  • safepoint:“A point in program where the state of execution is known by the VM”。不同JVM實現會選用不同的位置放置安全點。
  • 以HotSpot VM為例,在解釋器里每條字節碼的邊界都可以是一個安全點,因為HotSpot的解釋器總是能很容易的找出完整的“state of execution”。
  • 而在JIT編譯的代碼里,HotSpot會在所有方法的臨返回之前,以及所有非counted loop的循環的回跳之前放置安全點。
  • Serial收集器:

  • 特點:針對新生代;采用復制算法;單線程收集; “Stop The World”,即進行垃圾收集時,必須暫停所有工作線程,直到完成;
  • 應用場景:
  • 依然是HotSpot在Client模式下默認的新生代收集器;
  • 優勢:簡單高效(與其他收集器的單線程相比); 對于限定單個CPU的環境來說,Serial收集器沒有線程交互(切換)開銷,可以獲得最高的單線程收集效率;
  • 在用戶的桌面應用場景中,可用內存一般不大(< 200M),可以在較短時間內完成垃圾收集,只要不頻繁發生,這是可以接受的。
  • 設置參數:“-XX:+UseSerialGC”:添加該參數來顯式的使用串行垃圾收集器。
  • ParNew收集器:

  • 特點:ParNew垃圾收集器是Serial收集器的多線程版本。除了多線程外,其余的行為、特點和Serial收集器一樣,如:Serial收集器可用控制參數、收集算法、Stop The World、內存分配規則、回收策略等;
  • 應用場景:在Server模式下,ParNew收集器是一個非常重要的收集器,因為除Serial外,目前只有它能與CMS收集器配合工作。但在單個CPU環境中,不會比Serail收集器有更好的效果,因為存在線程交互開銷。
  • 設置參數:
  • “-XX:+UseConcMarkSweepGC”:指定使用CMS后,會默認使用ParNew作為新生代收集器;
  • “-XX:+UseParNewGC”:強制指定使用ParNew;
  • “-XX:ParallelGCThreads”:指定垃圾收集的線程數量,ParNew默認開啟的收集線程與CPU的數量相同。
  • 為什么只有Serial,ParNew能與CMS收集器配合?
  • CMS是HotSpot在JDK1.5推出的第一款真正意義上的并發(Concurrent)收集器,第一次實現了讓垃圾收集線程與用戶線程(基本上)同時工作;CMS作為老年代收集器,但卻無法與JDK1.4已經存在的新生代收集器Parallel Scavenge配合工作。
  • 因為Parallel Scavenge(以及G1)都沒有使用傳統的GC收集器代碼框架,而另外獨立實現;而其余幾種收集器則共用了部分的框架代碼。
  • Parallel Scavenge收集器-吞吐量(吞吐量收集器(Throughput Collector)):

  • 吞吐量(Throughput):CPU用于運行用戶代碼的時間與CPU總消耗時間的比值;
  • 即:吞吐量=運行用戶代碼時間 /(運行用戶代碼時間+垃圾收集時間); 高吞吐量即減少垃圾收集時間,讓用戶代碼獲得更長的運行時間;
  • 垃圾收集器期望的目標(關注點):
  • 停頓時間:停頓時間越短就適合需要與用戶交互的程序;良好的響應速度能提升用戶體驗;
  • 吞吐量:高吞吐量則可以高效率地利用CPU時間,盡快完成運算的任務;主要適合在后臺計算而不需要太多交互的任務;
  • 覆蓋區(Footprint):在達到前面兩個目標的情況下,盡量減少堆的內存空間;可以獲得更好的空間局部性;
  • 特點:有一些特點與ParNew收集器相似:新生代收集器;采用復制算法;多線程收集;
  • 主要特點:它的關注點與其他收集器不同。CMS等收集器的關注點是盡可能地縮短垃圾收集時用戶線程的停頓時間; 而Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量(Throughput)。
  • 應用場景:高吞吐量為目標,即減少垃圾收集時間,讓用戶代碼獲得更長的運行時間;
  • 當應用程序運行在具有多個CPU上,對暫停時間沒有特別高的要求時,即程序主要在后臺進行計算,而不需要與用戶進行太多交互; 例如:那些執行批量處理、訂單處理、工資支付、科學計算的應用程序。
  • GC參數設置:
  • “-XX:MaxGCPauseMillis“:控制最大垃圾收集停頓時間,大于0的毫秒數;MaxGCPauseMillis設置得稍小,停頓時間可能會縮短,但也可能會使得吞吐量下降;因為可能導致垃圾收集發生得更頻繁;
  • “-XX:GCTimeRatio”:設置垃圾收集時間占總時間的比率,0<n<100的整數; GCTimeRatio相當于設置吞吐量大小;垃圾收集執行時間占應用程序執行時間的比例的計算方法是:1 / (1 + n);例如,選項-XX:GCTimeRatio=19,設置了垃圾收集時間占總時間的5%==1/(1+19);默認值是1%==1/(1+99),即:n=99。
  • “-XX:+UseAdptiveSizePolicy”:開啟這個參數后,就不用手工指定一些細節參數,如:新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRation)、晉升老年代的對象年齡(XX:PretenureSizeThreshold)等;JVM會根據當前系統運行情況收集性能監控信息,動態調整這些參數,以提供最合適的停頓時間或最大的吞吐量, 這種調節方式稱為GC自適應的調節策略(GC Ergonomiscs);
  • 一種值得推薦的方式:
  • 只需設置好內存數據大小(如:"-Xmx"設置最大堆);然后使用"-XX:MaxGCPauseMillis"或"-XX:GCTimeRatio"給JVM設置一個優化目標;那些具體細節參數的調節就由JVM自適應完成。
  • 這也是Parallel Scavenge收集器與ParNew收集器一個重要區別。
  • 老年代收集器-Serial-old

  • 特點:針對老年代;采用"標記-整理"算法(還有壓縮,Mark-Sweep-Compact);單線程收集;
  • 應用場景:主要用于Client模式;而在Server模式有兩大用途:
  • 在JDK1.5及之前,與Parallel Scavenge收集器搭配使用(JDK1.6有Parallel Old收集器可搭配);
  • 作為CMS收集器的后備預案,在并發收集發生Concurrent Mode Failure時使用
  • Parallel Old收集器:Parallel Old垃圾收集器是Parallel Scavenge收集器的老年代版本

  • 特點:針對老年代;采用"標記-整理"算法; 多線程收集;
  • 應用場景:JDK1.6及之后用來代替老年代的Serial Old收集器; 特別是在Server模式,多CPU的情況下;這樣在注重吞吐量以及CPU資源敏感的場景,就有了Parallel Scavenge加Parallel Old收集器的"給力"應用組合;
  • 設置參數:"-XX:+UseParallelOldGC":指定使用Parallel Old收集器;
  • CMS收集器:并發標記清理(Concurrent Mark Sweep,CMS)收集器也稱為并發低停頓收集器(Concurrent Low Pause Collector)或低延遲(low-latency)垃圾收集器;

  • 特點:針對老年代;基于"標記-清除"算法(不進行壓縮操作,產生內存碎片); 以獲取最短回收停頓時間為目標;并發收集、低停頓;需要更多的內存(看后面的缺點);是HotSpot在JDK1.5推出的第一款真正意義上的并發(Concurrent)收集器;第一次實現了讓垃圾收集線程與用戶線程(基本上)同時工作;
  • 應用場景:與用戶交互較多的場景;希望系統停頓時間最短,注重服務的響應速度; 以給用戶帶來較好的體驗;如常見WEB、B/S系統的服務器上的應用;
  • 設置參數:"-XX:+UseConcMarkSweepGC":指定使用CMS收集器;
  • CMS收集器運作過程:
  • 初始標記(CMS initial mark):僅標記一下GC Roots能直接關聯到的對象; 速度很快;但需要"Stop The World";
  • 并發標記(CMS concurrent mark):進行GC Roots Tracing的過程;剛才產生的集合中標記出存活對象;應用程序也在運行;
  • 重新標記(CMS remark):為了修正并發標記期間因用戶程序繼續運作而導致標記變動的那一部分對象的標記記錄; 需要"Stop The World",且停頓時間比初始標記稍長,但遠比并發標記短;采用多線程并行執行來提升效率;
  • 并發清除(CMS concurrent sweep:回收所有的垃圾對象;整個過程中耗時最長的并發標記和并發清除都可以與用戶線程一起工作; 所以總體上說,CMS收集器的內存回收過程與用戶線程一起并發執行;
  • 明顯的缺點:
  • 對CPU資源非常敏感:并發收集雖然不會暫停用戶線程,但因為占用一部分CPU資源,還是會導致應用程序變慢,總吞吐量降低。CMS的默認收集線程數量是=(CPU數量+3)/4;當CPU數量多于4個,收集線程占用的CPU資源多于25%,對用戶程序影響可能較大;不足4個時,影響更大,可能無法接受。
  • 無法處理浮動垃圾,可能出現"Concurrent Mode Failure"失敗
  • *浮動垃圾(Floating Garbage):*在并發清除時,用戶線程新產生的垃圾,稱為浮動垃圾;這使得并發清除時需要預留一定的內存空間,不能像其他收集器在老年代幾乎填滿再進行收集; 也要可以認為CMS所需要的空間比其他垃圾收集器大;"-XX:CMSInitiatingOccupancyFraction":設置CMS預留內存空間;
  • "Concurrent Mode Failure"失敗:如果CMS預留內存空間無法滿足程序需要,就會出現一次"Concurrent Mode Failure"失敗; 這時JVM啟用后備預案:臨時啟用Serail Old收集器,而導致另一次Full GC的產生;
  • 產生大量內存碎片:由于CMS基于"標記-清除"算法,清除后不進行壓縮操作;產生大量不連續的內存碎片會導致分配大內存對象時,無法找到足夠的連續內存,從而需要提前觸發另一次Full GC動作。解決方法:
  • “-XX:+UseCMSCompactAtFullCollection”:使得CMS出現上面這種情況時不進行Full GC,而開啟內存碎片的合并整理過程; 但合并整理過程無法并發,停頓時間會變長;默認開啟(但不會進行,結合下面的CMSFullGCsBeforeCompaction);
  • “-XX:+CMSFullGCsBeforeCompaction”: 設置執行多少次不壓縮的Full GC后,來一次壓縮整理; 為減少合并整理過程的停頓時間;默認為0,也就是說每次都執行Full GC,不會進行壓縮整理;
  • 由于空間不再連續,CMS需要使用可用"空閑列表"內存分配方式,這比簡單實用"碰撞指針"分配內存消耗大; 總體來看,與Parallel Old垃圾收集器相比,CMS減少了執行老年代垃圾收集時應用暫停的時間; 但卻增加了新生代垃圾收集時應用暫停的時間、降低了吞吐量而且需要占用更大的堆空間;
  • G1收集器:JDK7-u4才推出商用的收集器

  • 特點:
  • 并行與并發:能充分利用多CPU、多核環境下的硬件優勢; 可以并行來縮短"Stop The World"停頓時間; 也可以并發讓垃圾收集與用戶程序同時進行;
  • 分代收集,收集范圍包括新生代和老年代: 能獨立管理整個GC堆(新生代和老年代),而不需要與其他收集器搭配; 能夠采用不同方式處理不同時期的對象;雖然保留分代概念,但Java堆的內存布局有很大差別;將整個堆劃分為多個大小相等的獨立區域(Region);新生代和老年代不再是物理隔離,它們都是一部分Region(不需要連續)的集合;
  • 結合多種垃圾收集算法,空間整合,不產生碎片從整體看,是基于標記-整理算法;從局部(兩個Region間)看,是基于復制算法; 這是一種類似火車算法的實現;都不會產生內存碎片,有利于長時間運行;
  • 可預測的停頓:低停頓的同時實現高吞吐量,G1除了追求低停頓處,還能建立可預測的停頓時間模型;可以明確指定M毫秒時間片內,垃圾收集消耗的時間不超過N毫秒;
  • 應用場景: 面向服務端應用,針對具有大內存、多處理器的機器;最主要的應用是為需要低GC延遲,并具有大堆的應用程序提供解決方案; 如:在堆大小約6GB或更大時,可預測的暫停時間可以低于0.5秒;用來替換掉JDK1.5中的CMS收集器;在下面的情況時,使用G1可能比CMS好:
  • 超過50%的Java堆被活動數據占用;
  • 對象分配頻率或年代提升頻率變化很大;
  • GC停頓時間過長(長于0.5至1秒)。
  • 設置參數
  • “-XX:+UseG1GC”:指定使用G1收集器;
  • “-XX:InitiatingHeapOccupancyPercent”:當整個Java堆的占用率達到參數值時,開始并發標記階段;默認為45;
  • " -XX:MaxGCPauseMillis":為G1設置暫停時間目標,默認值為200毫秒;
  • “-XX:G1HeapRegionSize”:設置每個Region大小,范圍1MB到32MB;目標是在最小Java堆時可以擁有約2048個Region;
  • 為什么G1收集器可以實現可預測的停頓:
  • 可以有計劃地避免在Java堆的進行全區域的垃圾收集;
  • G1跟蹤各個Region獲得其收集價值大小,在后臺維護一個優先列表;
  • 每次根據允許的收集時間,優先回收價值最大的Region(名稱Garbage-First的由來);
  • 這就保證了在有限的時間內可以獲取盡可能高的收集效率;
  • G1收集器運作過程:
  • 初始標記(Initial Marking): 僅標記一下GC Roots能直接關聯到的對象;且修改TAMS(Next Top at Mark Start),讓下一階段并發運行時,用戶程序能在正確可用的Region中創建新對象;需要"Stop The World",但速度很快;
  • 并發標記(Concurrent Marking): 進行GC Roots Tracing的過程;剛才產生的集合中標記出存活對象;耗時較長,但應用程序也在運行;并不能保證可以標記出所有的存活對象;
  • 最終標記(Final Marking): 為了修正并發標記期間因用戶程序繼續運作而導致標記變動的那一部分對象的標記記錄;上一階段對象的變化記錄在線程的Remembered Set Log;這里把Remembered Set Log合并到Remembered Set中;需要"Stop The World",且停頓時間比初始標記稍長,但遠比并發標記短; 采用多線程并行執行來提升效率;
  • 篩選回收(Live Data Counting and Evacuation): 首先排序各個Region的回收價值和成本;然后根據用戶期望的GC停頓時間來制定回收計劃; 最后按計劃回收一些價值高的Region中垃圾對象;回收時采用"復制"算法,從一個或多個Region復制存活對象到堆上的另一個空的Region,并且在此過程中壓縮和釋放內存;可以并發進行,降低停頓時間,并增加吞吐量;
  • JVM常用啟動參數:

  • -Xmx1024m,-Xmx1g 單位(g,m,k)
  • -Xms512m
  • -Xmn256m(相當于將新生代的初始、最小、最大值設置為同一個:-XX:NewSize = -XX:MaxNewSize)
  • -Xss512k
  • -XX:PretenureSizeThreshold,大于這個數量直接在老年代分配,缺省為0 表示不會直接分配在老年代;(注:如果在新生代分配失敗且對象是一個不含任何對象引用的大數組,也可被直接分配到老年代。)
  • -XX:-DisableExplicitGC,禁用顯示GC,System.gc()
  • -XX:+PrintGCDetails,打印GC詳情
  • -XX:+PrintGCTimeStamps : JVM啟動到GC開始經歷的時間
  • -XX:+PrintGCDateStamps : GC發生的具體時間點
  • -XX:+PrintCommandLineFlags: 讓JVM打印出那些已經被用戶或者JVM設置過的詳細的XX參數的名稱和值。
  • -XX:NewRatio=2,老年代和新生代的內存比例為2:1
  • -XX:SurvivorRatio=8,表示eden和1個survivor區的比例,survivor大小 = Xmn/(SurvivorRatio+2)
  • -Dxxx=yyy,啟動時配置系統屬性,在java中通過System.getProperty(“xxx”)獲取相應的值
  • 總結

    以上是生活随笔為你收集整理的jvm垃圾回收之垃圾收集器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。