GC 為什么要掛起用戶線程? 什么愁什么怨?


GC 為什么要掛起用戶線程? 什么愁什么怨?

img

前言

JVM 系列文章的第一篇。敬請期待后續。

故障描述

某年某月某日 上午,線上發生故障,經過排查,發現某核心服務 Dubbo 接口超時。

img

故障根源

查看該服務監控指標,發現該服務 FullGC 次數過於頻繁,簡直要上天了。那也難怪接口會超時了。

那么為啥 FullGC 次數太多會造成接口超時呢?

因為 GC 停頓。 FullGC 時會產生GC停頓,也叫 stop the world。簡稱 STW ,是指在執行垃圾收集算法時,用戶線程都被掛起。這也不難理解為啥 頻繁 FullGC 會引起服務超時了。

深入探究

那么為什么會引起頻繁FullGC 呢?

回答這個問題之前,先了解下,有哪些情況會觸發 Full GC ?

  1. 老年代內存空間不足時,會觸發 FullGC.
  2. 永久代/metaspace 內存空間不足時,也會觸發FullGC.
  3. 顯示調用 GC,System.gc().(會建議jvm GC,但是不一定會GC).

產生 FullGC 的基本原因就上面三種。

故障服務就是創建很多對象,無法回收,導致內存不足,然后 GC 回收不了時,就會引起頻繁 FullGC 了。

復現故障

根據內存不足創建對象會引起 FullGC 的原理,寫了一個 Demo ,觀察GC 情況。

代碼如下:

img

代碼很簡單,就是讓上次創建的對象可以被回收,然后繼續創建對象,然后鏈接到根結點,使其不會被回收。demo 地址

使用啟動參數 -Xms512m -Xmx512m 設置堆內存大小。

啟動 Demo ,然后發起請求,觀察GC 情況。

首先,使用命令 jps -l 查看進程ID

img

然后使用 jstat 命令查看GC信息 (jstat 命令詳解):

img

上圖可以看到 正在不停的進行 Full GC.

img

上圖可以看出,老年代,以及元數據區 內存空間已滿,這也是 不停 Full GC 的原因。

再看我發出的請求:

img

過去這么久,依然沒有結果。

使用 jstack 命令查看 線程狀態,發現 用戶線程已經被掛起。

img

不難看出,頻繁的 FullGC 已經影響到了應用的正常運行。

結束語

了解 JVM 還是很有必要的。CURD 不覺得什么,問題來臨時就可以so easy 了。

img


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM