您好,登錄后才能下訂單哦!
這篇文章主要介紹java中依賴包濫用System.gc()導致的頻繁Full GC怎么辦,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
業務部門的一個同事遇到個奇怪的 Full GC 問題,有個服務遷移到新的應用后,一直頻繁 Full GC。新應用機器的配置是 4c 8g,老應用是 4c 4g,老應用 GC 都很正常,并且代碼沒有變更,所以比較奇怪。
問題的現象是,從監控圖上看一直有大量的 Full GC
遇到這個問題,一般都是先看看各個區的內存占用情況:
從監控圖上看 Old Gen、Young Gen、Perm Gen,沒什么問題,不會觸發 Full GC,當然這里看各個 Gen 是否會觸發 Full GC 需要結合 JVM 參數配置來看。
順便也看了下 GC 日志,一直狂暴 CMS GC 日志,而且可以看到老年代使用空間也不大,細心可以發現,大量的 CMS GC 中夾雜著 Young、Perm 區的回收,所以其實是 Full GC。GC 日志如下:
老應用的 JVM 參數配置
新應用的 JVM 參數配置
通過上面的觀察,再根據一般觸發 CMS GC 幾個可能性:
Old Gen 使用達到一定的比率,默認為92%,這里看 CMSInitiatingOccupancyFraction=80%,而實際才使用 2%(看監控圖表)不到,所以排除這種情況。
配置了 CMSClassUnloadingEnabled,且 Perm Gen 的使用達到一定的比率默認為 92%,這里看 CMSInitiatingPermOccupancyFraction=80%,而實際才使用 30%(看監控圖表)不到,所以排除這種情況。
配置了 ExplictGCInvokesConcurrent 且未配置 DisableExplicitGC 的情況下顯示調用了 System.gc()。
Hotspot 自己根據估計決定是否要觸法,如 CMS 悲觀策略,這類可以通過 GC 日志分析。
大致判斷很可能是 System.gc() 導致的問題,但是怎么定位調用 System.gc() 的代碼呢? 當時就想如果是 System.gc() 引起的頻繁 Full GC,jstack 線程堆棧應該能看到一些信息,果不其然,確實通過線程堆棧找到了。
jstack 作用非常大,很多問題都能從這里發現,而且比較輕量,對應用基本無影響。某次的 jstack 信息只代表那個時刻的線程堆棧,有時只看一個 jstack 信息可能看不出什么問題,一般可以多 jstack 幾次,然后對比去看,基本就能發現一些問題。 (當然該問題,也可能不是頻繁的 Full GC,可能通過 jstack 定位不到問題,可以 jstat -gccause pid 1000,來查看 gc 原因。)
很明顯,是由于 jxl 這個包中的 close 方法顯示調用了 System.gc() 導致的問題。
跟了下代碼,自然確實存在這段代碼,不過有個設置開關,可以 disable 這個功能,所以在使用的時候可以設置 setGCDisabled(true),關閉觸發 System.gc()。
但是為什么老應用沒有問題呢,主要是因為它 -XX:+DisableExplicitGC,屏蔽了 System.gc() 動作,新應用的 JVM 沒有這個配置。
可能大家還有個疑問,都知道 System.gc() 會觸發 Full GC,那為什么一直進行 CMS GC(通過GC日志)呢? 主要是因為這個參數 -XX:+ExplicitGCInvokesConcurrent,打開此參數后,會做并行 Full GC,只有配置 -XX:+UseConcMarkSweepGC 這個參數,該參數才會生效。因此,System.gc() 時 Old 區會進行 CMS GC,可提高 Full GC 效率。
以上是“java中依賴包濫用System.gc()導致的頻繁Full GC怎么辦”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。