柚子快報邀請碼778899分享:java JVM:垃圾回收
柚子快報邀請碼778899分享:java JVM:垃圾回收
JVM垃圾回收的核心:如何判斷對象能否被回收;如何回收。
如何判斷一個對象是否可以回收?
方法中無法引用對象,即可回收。判斷一個對象是否還有引用?
1.引用計數(shù)法
每次引用和清除引用修改引用計數(shù)器,頻繁引用和清除引用時降低效率,無法解決循環(huán)引用。
2.可達性分析
核心思想:
對象分類:GC Root對象、普通對象以GC Root對象為起點,開始向下搜索,搜索不到的對象不可達,可以被回收
哪些對象是GC Root對象?
線程對象,引用線程棧幀中的方法參數(shù),局部變量等。(可以理解為:虛擬機棧/本地方法棧引用的對象)系統(tǒng)類加載器加載的java.lang.Class對象,引用類中的靜態(tài)變量。(可以理解為:方法區(qū)中類靜態(tài)屬性引用對象和常量引用對象)被同步鎖持有的對象JNI(本地方法接口)引用的對象(本地方法調(diào)用時使用的全局對象)
判斷完一個對象能否被回收后,該怎么回收這些對象呢?
垃圾回收算法
核心思想:找到內(nèi)存中存活對象和可回收對象;釋放不在存活對象內(nèi)存
評價標準:吞吐量、最大STW、堆使用效率
1.標記清除算法
標記存活對象,在標記完成后統(tǒng)一回收掉所有沒有被標記的對象。
優(yōu):簡單
缺:碎片化;標記和清除兩個過程效率都不高
2.復制算法
準備兩個空間,F(xiàn)rom和To空間,將存活對象搬運到另一塊
優(yōu):不會產(chǎn)生內(nèi)存碎片
缺:可用內(nèi)存變?。徊贿m合老年代(如果存活數(shù)量比較大,復制性能變差)
3.標記-整理算法
標記存活對象,將存活對象移動到堆的另一端
優(yōu):不會產(chǎn)生內(nèi)存碎片;內(nèi)存使用效率高
缺:整理階段效率不高
4.分代GC
將內(nèi)存區(qū)域劃分為年輕代(Eden、S0、S1)和老年代,這樣可以根據(jù)不同年代的特點選擇合適的垃圾回收算法。
年輕代每次收集都會有大量對象死去,可以選擇標記-復制算法。老年代的對象存活率高,且沒有額外的空間對它進行分配擔保,所以必須選擇標記清除或標記整理算法。
垃圾回收器
HotSpot虛擬機實現(xiàn)的垃圾回收器:jdk8:Parallel Scavenge + Parallel Old、jdk9~jdk20:G1
搭配關系:
Serial+Serial Old
單線程串行回收。只使用一條垃圾回收線程,工作時暫停其他工作線程。
年輕代:標記-復制算法;老年代:標記整理算法。 -XX:+UseSerialGC
優(yōu):簡單高效,單cpu下吞吐量出色。
缺:多cpu下吞吐量不如其它,堆偏大會讓用戶線程等待太久。
ParNew
對Serial在多cpu下的優(yōu)化,使用多線程進行垃圾回收,回收時暫停其它工作線程
新生代采用標記-復制算法 -XX:+UseParNewGC
優(yōu):多cpu下停頓時間較短
缺:吞吐量和停頓時間不如G1
適應場景:JDK8及之前版本與CMS搭配使用
CMS
允許用戶線程和垃圾回收線程在某些步驟中同時進行,減少用戶線程等待
老年代:標記清除算法
優(yōu):并發(fā)收集、低停頓
缺:對 CPU 資源敏感;無法處理浮動垃圾;產(chǎn)生空間碎片。
初始標記:記錄下直接與 GCroot 相連的對象,速度很快
并發(fā)標記:用一個閉包結構去記錄可達對象,但在這個階段結束,這個閉包結構并不能保證包含當前所有的可達對象。因為用戶線程可能會不斷的更新引用域,所以 GC 線程無法保證可達性分析的實時性。所以這個算法里會跟蹤記錄這些發(fā)生引用更新的地方。
重新標記:修正并發(fā)標記期間因為用戶程序繼續(xù)運行而導致標記產(chǎn)生變動的那一部分對象的標記記錄,時間遠比并發(fā)標記短
并發(fā)清除:開啟用戶線程,同時 GC 線程開始對未標記的區(qū)域做清掃。
Parallel Scavenge +?Parallel Old
多線程并行回收,自動調(diào)整堆內(nèi)存大小。
Parallel Scavenge垃圾收集器達到可控吞吐量的核心在于它提供了兩個重要的調(diào)優(yōu)參數(shù),使得開發(fā)者可以調(diào)整這些參數(shù)以達到期望的吞吐量和暫停時間的平衡。這兩個參數(shù)是:吞吐量(Throughput):通過參數(shù)-XX:GCTimeRatio來控制;最大暫停時間(Maximum Pause Time):通過參數(shù)-XX:MaxGCPauseMillis來控制。
年輕代:標記-復制;老年代采用標記-整理。-XX:+UseParallelGC、-XX:+UseParallelOldGC
優(yōu):并發(fā)收集,多核cpu下效率較高
缺:暫停時間長
G1
優(yōu):
預測性能停頓時間:用戶可以指定所期望的停頓時間(Pause Time Goal)。并行和并發(fā)執(zhí)行:G1利用多核處理器的優(yōu)勢,同時執(zhí)行垃圾回收操作,大部分工作都是并行進行的。此外,G1的某些階段可以與應用程序線程同時運行(并發(fā)),減少停頓時間。增量處理:G1不需要一次性完成所有的垃圾回收,這有助于系統(tǒng)的響應性。它將堆劃分為多個區(qū)域(Region),并根據(jù)每個區(qū)域的垃圾回收優(yōu)先級來選擇性地進行清理??臻g整理:整體采用標記整理算法,以避免碎片??绱占篏1同時管理年輕代和老年代的垃圾回收。
造成頻繁full gc可能的原因?
內(nèi)存泄漏:應用中存在內(nèi)存泄漏,導致不再使用的對象無法被GC回收,隨著時間的推移,堆內(nèi)存不斷增加,觸發(fā)頻繁的Full GC。老年代內(nèi)存不足:老年代分配的內(nèi)存太小,無法滿足應用運行時長時間存活對象的需要,導致老年代快速填滿而觸發(fā)Full GC。大對象頻繁創(chuàng)建:頻繁創(chuàng)建大對象(特別是大于年輕代Eden區(qū)的對象),這些對象直接分配到老年代,導致老年代快速耗盡。不合理的gc策略或配置:JVM的GC策略或相關參數(shù)(如堆大小、新生代與老年代的比例、GC算法選擇等)設置不合理,可能導致GC效率低下,引發(fā)頻繁Full GC。JVM版本問題
頻繁full gc如何排查?
排查 Full GC 的原因通常需要結合日志分析、監(jiān)控工具和一些診斷命令。
開啟GC日志:
通過在JVM啟動參數(shù)中添加如 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:
分析GC日志:
使用GC日志分析工具(如 GCEasy、GCViewer 或 JClarity's Censum)來分析GC日志文件。這些工具可以幫助你快速識別GC活動的模式、頻率、暫停時間以及可能的內(nèi)存泄漏。
監(jiān)控堆內(nèi)存使用情況:
使用JVisualVM、JMC(Java Mission Control)等工具實時監(jiān)控Java堆的使用情況。特別關注老年代(Old Gen)的使用率,因為老年代的滿載往往是觸發(fā)Full GC的直接原因。
檢查外部因素:
檢查是否有外部系統(tǒng)調(diào)用(如數(shù)據(jù)庫查詢、外部服務調(diào)用)導致的延遲增加或資源占用,這些都可能間接影響到JVM的性能和GC行為。
檢測內(nèi)存泄漏:
如果發(fā)現(xiàn)Full GC后堆內(nèi)存的使用率并沒有顯著下降,或者老年代的使用量持續(xù)增加,這可能是內(nèi)存泄漏的跡象。使用堆分析工具(HeapDump)來分析內(nèi)存占用,找出泄漏對象。
優(yōu)化GC策略和JVM參數(shù):
根據(jù)分析結果調(diào)整JVM參數(shù),可能需要調(diào)整的參數(shù)包括堆大?。?Xms 和 -Xmx)、新生代和老年代的比例、使用的GC收集器類型等,以減少Full GC的發(fā)生頻率和減少暫停時間。
代碼級別的優(yōu)化:
如果發(fā)現(xiàn)特定代碼路徑導致了大量的臨時對象創(chuàng)建或者較大對象的頻繁分配,考慮進行代碼優(yōu)化,如重用對象、優(yōu)化數(shù)據(jù)結構和算法等。
升級JVM版本:
在某些情況下,升級到更高版本的JVM可以幫助解決已知的性能問題或GC問題,因為新版本的JVM可能包含更優(yōu)的GC算法和性能改進。
通過這些步驟,你可以較為系統(tǒng)地識別和解決導致 Full GC 的原因,從而優(yōu)化應用的性能。
軟引用中的對象在內(nèi)存不足時被回收,這時如何回收軟引用對象本身?
SoftReference提供了一套隊列機制:
軟引用創(chuàng)建時,通過構造器傳入引用隊列軟引用中包含的對象被回收時,該軟引用對象本身進入引用隊列
通過代碼遍歷引用隊列,將SoftReference的強引用刪除
柚子快報邀請碼778899分享:java JVM:垃圾回收
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉載請注明,如有侵權,聯(lián)系刪除。