系統一個小時多次Full GC,導致系統線程停止運行,影響系統的性能,可靠性

背景:

某一天系統出現了請求超時,然后通過日志查看,程序執行到某一個位置,直接停下來來了,或者說所有的線程的執行都停下來了。而且是該時間段,請求處理變慢。排查相關的服務,并沒有出現死鎖,異常,內存不足的情況,并且不是特定的接口超時,而且超時的時間也比較散亂。于是有同事提出來有沒有可能系統正在做full GC。于是我們開始朝著這個方向排查。

確定請求超時的原因

第一步:獲取GClog:通過GClog于請求超時的時間段對比,發現請求超時的時間,系統真正進行fullGC。??STW 機制的本質??Full GC 需掃描并清理??整個堆內存??(包括新生代、老年代、元空間),為確保垃圾回收過程中對象引用關系的一致性,JVM ??必須暫停所有應用線程??。這種全局暫停稱為 STW(Stop-The-World)。

??表現??:所有用戶請求卡頓、任務隊列堆積、監控指標顯示線程狀態為 BLOCKED或 WAITING。
??耗時??:通常持續 ??百毫秒至數秒??,堆越大、存活對象越多,暫停時間越長(例如 10GB 堆可能暫停 5 秒以上)。

而且每一次的full GC都是長達:5-6 s 也就線程暫停了5-6s。并且每次超時都是在full GC發生的時候,所以基本上可以確認就是full GC導致的。 GC導致的系統卡頓的特點:1. 無特定服務 2.通過系統執行日志發現線程執行情況 3.通過GC日志判斷

確定full GC的原因

1.確定了GC導致的系統吞吐量降低,延遲抬升,接下來需要解決full GC的問題。

導致full GC的原因一般有哪些?
1.首先建議你們自習看GClog,因為好的GClog他會直接告訴你full GC的原因。
2.其次你也需要知道哪些會導致full GC,

第一:內存空間不足
1.老年代空間不足、元空間溢出、新生代晉升壓力
第二: 顯示觸發
System.gc()

其實GClog已經給了原因:reason:sys,其實就告訴是system.gc導致的,其實也有遇到內存空間不足的情況,給的原因:reason:af(allocation fail)分配失敗,也就是分配老年代空間不足。

也可以通過gc log 里面的老年代的空間進行分析,會發現在system.gc 前,heap size 在gc前有很多的空間,而且老年代也夠的。那么其實就可以判斷不是第一個原因,而是第二個原因。

但是System.gc()是誰發起的呢?首先全局搜索代碼,我們的業務代碼并沒有直接調用System.gc(),那么會是什么觸發System.gc()呢。以及我們能不能直接禁用System.gc()。

System.gc()可以直接禁用嘛

首先不建議禁用System.gc(),因為有可能你使用的第三方的框架,或者你以來的組建需要通過System.gc(),清理對內內存。

比如: ??
堆外內存回收依賴??
??DirectByteBuffer 等堆外內存??:其清理依賴于關聯的 Cleaner對象被 GC 回收。若禁用 System.gc(),堆外內存可能無法及時釋放,導致 OutOfMemoryError(即使堆內存充足)。??典型案例??:Netty 等NIO 框架需定期觸發 Full GC 釋放堆外內存。禁用后可能需等待 JVM 自動觸發 Full GC,延遲釋放可能引發內存溢出。

System.gc()原因排查

那么如果不禁用,我們應該怎么做?到了這里我們的解決思路是什么?這里提到了直接內存,那有沒有可能就是直接內存不夠導致的fullGC呢?如果是這個懷疑那怎么證明?直接內存不足?那直接內存使用了多少?于是我們想到,不如打印直接內存看看,看看使用情況,以及我們可以結合GClog再進一步觀察一下。其實如果對直接內存熟悉的同學,不一定需要打印,GClog里面會有一個虛引用的數量,虛引用和直接內存又是什么關系呢?

虛引用是管理直接內存的“監控觸發器”?

??虛引用的作用??虛引用是 Java 中最弱的引用類型(PhantomReference),??無法通過 get()獲取對象實例??(始終返回 null),其主要功能是??跟蹤對象被垃圾回收的時機??。虛引用必須與 ReferenceQueue關聯,當對象被 GC 回收時,虛引用會被加入隊列,從而觸發后續清理操作。 人話:目標對象被GC回收,目標對象的虛引用會加入隊列,觸發后續動作。

直接內存的特殊性??直接內存(如 DirectByteBuffer分配的內存)位于 JVM 堆外,由操作系統管理。??其生命周期不受 JVM 垃圾回收器直接控制??,但堆內的 DirectByteBuffer對象本身是受 GC 管理的。當該對象被回收時,其關聯的直接內存需要手動釋放(通過 Cleaner機制),否則會導致??堆外內存泄漏。

??監控對象回收??:虛引用綁定到 DirectByteBuffer對象上,當該對象被 GC 回收時,虛引用被加入 ReferenceQueue。
??觸發資源釋放??:通過輪詢 ReferenceQueue,程序可執行堆外內存的釋放(如調用 Unsafe.freeMemory())。
??防止內存泄漏??:此機制確保堆外內存不會因對象回收而遺留未釋放的資源。

堆內:DirectByteBuffer對象 – 虛引用 – 堆外內存。所以可以理解是一種橋梁。

DBBs use a PhantomReference which is essentially a more flexible finalizer and they allow the native memory of the DBB to be freed once there are no longer any live Java references. Finalizers and their ilk are generally not recommended because their cleanup time by the garbage collector is non-deterministic.

所以聊到這里我們也會發現,其實通過GC,清理DirectByteBuffer對象,虛引用被加入 ReferenceQueue,進而清理堆外內存的空間。所以達到了JVM對堆外內存的控制。 所以你可以通過判斷虛引用的數量,判斷DirectByteBuffer對象數量,雖然只是數量,但你也可以間接判斷堆外內存的使用情況。

import java.lang.management.ManagementFactory;
import java.lang.management.BufferPoolMXBean;
import java.util.List;public class DirectMemoryMonitor {public static void main(String[] args) {List<BufferPoolMXBean> pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);for (BufferPoolMXBean pool : pools) {if ("direct".equals(pool.getName())) {System.out.println("直接內存使用: " + formatBytes(pool.getMemoryUsed()) + " / " + formatBytes(pool.getTotalCapacity()));}}}private static String formatBytes(long bytes) {if (bytes < 1024) return bytes + " B";int exp = (int) (Math.log(bytes) / Math.log(1024));char unit = "KMGTPE".charAt(exp-1);return String.format("%.1f %sB", bytes / Math.pow(1024, exp), unit);}
}

打印成功后發現:當直接內存達到64M,96M,128M的時候系統就會發生full GC。所以到這里我們通過直接內存的使用情況初步懷疑就是直接內存不足導致的。我們使用的是IBM JDK 1.8所以我們也咨詢了IBM的同事,他們給我們丟了一個鏈接:

https://publib.boulder.ibm.com/httpserv/cookbook/WebSphere_Application_Server-WAS_traditional-HTTP.html

https://publib.boulder.ibm.com/httpserv/cookbook/Troubleshooting-Troubleshooting_Java.html#Troubleshooting-Troubleshooting_Java-Excessive_Direct_Byte_Buffers

There are two main types of problems with Direct Byte Buffers:

Excessive native memory usage
Excessive performance overhead due to System.gc calls by the DBB code

This section primarily discusses issue 1. For issue 2, note that IBM Java starts with a soft limit of 64MB and increases by 32MB chunks with a System.gc each time, so consider setting -XX:MaxDirectMemorySize=$BYTES (e.g. -XX:MaxDirectMemorySize=1024m) to avoid this upfront cost (although read on for how to size this).

This type of problem is particularly bad with generational collectors because the whole purpose of a generational collector is to minimize the collection of the tenured space (ideally never needing to collect it). If a DBB is tenured, because the size of the Java object is very small, it puts little pressure on the tenured heap. Even if the DBB is ready to be garbage collected, the PhantomReference can only become ready during a tenured collection. Here is a description of this problem (which also talks about native classloader objects, but the principle is the same):(人話:如果DBB已經進入了老年代,除非full GC 回收老年代空間,否則不會回收DBB,從而導致DBB泄漏)

In most cases, something like -XX:MaxDirectMemorySize=1024m (and ensuring -Xdisableexplicitgc is not set) is a reasonable solution to the problem.

A system dump or HPROF dump may be loaded in the IBM Memory Analyzer Tool & the IBM Extensions for Memory Analyzer DirectByteBuffer plugin may be run to show how much of the DBB native memory is available for garbage collection. For example:

規律基本上對上了,至此可以得出結論:堆外內存不足,導致的顯示GC的發生。

所以至此我們需要解決的就是DBB的問題:

這里的解決方案:

1.通過設置DBB的大小,給一個1G,如果不是DBB的泄漏問題,可以通過minor GC或者major GC清理空間,從而清理直接內存,而由于給了1G就不會因為達到了64M,96M等進行full GC了。總的來說就是:不那么容易滿,加強一下GC清理多一些DBB,趕上DBB增加的速度。

加強一下GC清理多一些,如何清理多一些呢?

2.打印分配的DBB的tracelog看看誰在分配,其實我們也打印了發現IBM WAS底層很多地方都在使用DBB。所以很難阻止。
IBM WAS也給我們一個參數減少在HTTP請求中使用DBB,但是代價就是處理會變慢一些。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92022.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用OMV+NextCloud搭建私有云

原文地址&#xff1a;使用OMVNextCloud搭建私有云 – 無敵牛 歡迎參觀我的網站&#xff1a;無敵牛 – 技術/著作/典籍/分享等 OpenMediaVault&#xff08;簡稱OMV&#xff09;是一款基于Debian的開源網絡存儲&#xff08;NAS&#xff09;操作系統&#xff0c;提供Web管理界面&…

Codeforces Round 1008 (Div. 2)

A. Final Verdict 題目大意 給你一個數組a&#xff0c;每次把他拆分為等長的k個子序列&#xff0c;然后用子序列的平均數替換掉這個子序列&#xff0c;問最后能不能讓數組只剩下一個數字x 解題思路 無論怎么劃分&#xff0c;最后的總值是不變的&#xff0c;所以只需要看總和…

python轉移安裝目錄到D盤

遷移python安裝路徑第一步&#xff1a;移動目錄第二步&#xff1a;修改環境變量之前沒有設置之前設置過第一步&#xff1a;移動目錄 源路徑&#xff1a; C:\Users\Emma.ZRF\AppData\Local\Programs\Python\Python38 原環境變量 C:\Users\Emma.ZRF\AppData\Local\Programs\Pyth…

C#垃圾回收機制:原理與實踐

C#垃圾回收機制:原理與實踐 一、垃圾回收:C#內存管理的“幕后功臣”? 二、GC的核心引擎:基于代的優化策略 三、Demo展示 1. 簡單對象的垃圾回收示例 2. 基于代的回收示例 四、常用方法 五、推薦使用的場景 六、注意事項 管住手:避免濫用 GC.Collect() 析構函數:保持輕量 …

基于SpringBoot+MyBatis+MySQL+VUE實現的名城小區物業管理系統(附源碼+數據庫+畢業論文+開題報告+部署教程+配套軟件)

摘要 當下&#xff0c;正處于信息化的時代&#xff0c;許多行業順應時代的變化&#xff0c;結合使用計算機技術向數字化、信息化建設邁進。以前相關行業對于物業信息的管理和控制&#xff0c;采用人工登記的方式保存相關數據&#xff0c;這種以人力為主的管理模式已然落后。本人…

3DXML 轉換為 UG 的技術指南及迪威模型網在線轉換推薦

一、3DXML 轉換為 UG 的必要性 &#xff08;一&#xff09;軟件功能利用需求 3DXML 格式由達索系統開發&#xff0c;主要用于在其相關產品&#xff08;如 CATIA、SOLIDWORKS 和 3DEXPERIENCE 等&#xff09;中進行 3D 數據交換與輕量化可視化。它雖然能夠很好地在達索生態內實…

無人機光伏巡檢缺陷檢出率↑32%:陌訊多模態融合算法實戰解析

原創聲明本文為原創技術解析&#xff0c;引用來源標注 “陌訊技術白皮書”&#xff0c;禁止未經授權的轉載與改編。摘要在無人機光伏巡檢場景中&#xff0c;邊緣計算優化與復雜場景魯棒性是提升檢測效率的核心挑戰。本文解析陌訊多模態融合算法在光伏板熱斑、隱裂等缺陷檢測中的…

倉庫管理系統-15-前端之管理員管理和用戶管理

文章目錄 1 后臺查詢用戶列表 1.1 null和空字符串的檢查 1.2 UserController.java 2 管理員管理 2.1 傳遞參數roleId=1 2.2 admin/AdminManage.vue 3 用戶管理 3.1 傳遞參數roleId=2 3.2 user/UserManage.vue 管理員管理和用戶管理,與之前的Main.vue的內容基本一致,無非是管理…

個人筆記UDP

UDP消息發送發送端? import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; ? //不需要連接服務器 public class UdpClientDemo01 {public static void main(String[] args) throws Exception {/…

26屆算法秋招_baidu筆試_算法編程題。

給定2個字符串str1、str2&#xff0c;計算把str1轉變為str2的最小操作數。可執行的操作有&#xff1a;插入一個字符修改一個字符刪除一個字符解題&#xff1a;這是一個經典的編輯距離問題&#xff0c;通常使用動態規劃解決。定義dp[i][j]表示將str1的前i個字符轉換為str2的前j個…

uniapp-vue3來實現一個金額千分位展示效果

前言&#xff1a;uniapp-vue3來實現一個金額千分位展示效果實現效果&#xff1a;實現目標&#xff1a;1、封裝組件&#xff0c;組件內部要實現&#xff0c;input輸入金額后&#xff0c;聚焦離開后&#xff0c;金額以千分位效果展示&#xff0c;聚焦后展示大寫金額的彈框隨時寫的…

途游Android面試題及參考答案

對 Java 面向對象的理解是什么?多態的實現方法有哪些? Java 面向對象是一種編程思想,核心在于將現實世界中的事物抽象為 “對象”,每個對象由 “屬性”(數據)和 “方法”(行為)組成,通過對象之間的交互完成功能。其核心特性包括封裝、繼承和多態: 封裝是指將對象的屬…

通過filezilla在局域網下實現高速傳輸數據

一. filezilla安裝 1.1 linux安裝 sudo apt update sudo apt install openssh-server1.2 windows安裝 windows安裝可以參考這篇文章 二. 使用方法 2.1 wifi下使用方法 直接查看想要連接的電腦的ip&#xff0c;其他的按照有線網絡設置好了ip之后進行連接就行。 2.2 有線網…

python的易物小店交換系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 在需求分…

[硬件電路-119]:模擬電路 - 信號處理電路 - 比較器,模擬電路中的“決策者”,模擬信號到數字電平邏輯信號的轉化者...

前言&#xff1a;比較器的價值1、為何稱比較器為“決策者”&#xff1f;邏輯判斷的物理實現比較器通過硬件電路直接完成“大于/小于”的二元判斷&#xff0c;無需軟件干預。例如&#xff1a;在過壓保護電路中&#xff0c;比較器實時監測輸入電壓 Vin? 與參考電壓 Vref?&#…

【從零開始學習Redis】初識Redis

初識Redis 一句話理解Redis&#xff1a; Redis是一個基于內存的、支持多種數據結構的高性能鍵值數據庫&#xff0c;常被用于緩存、分布式鎖和消息隊列。和 MySQL 的區別&#xff1a;特點RedisMySQL類型非關系型&#xff08;NoSQL&#xff09;關系型&#xff08;SQL&#xff09;…

CUDA雜記--nvcc使用介紹

nvcc 是 NVIDIA CUDA 生態的核心編譯器&#xff0c;負責將 CUDA C/C 代碼&#xff08;混合了主機代碼和設備代碼&#xff09;編譯為可在 CPU 和 GPU 上運行的二進制文件。它不僅是一個簡單的編譯器&#xff0c;更是一個“編譯驅動程序”&#xff0c;協調多個工具鏈&#xff08;…

Codeforces Round 1040 (Div. 2)(補題)

文章目錄前言A.Submission is All You NeedB. PathlessC.Double PerspectiveD.Stay or Mirror前言 又被卡在第二題了&#xff0c;當時腦子跟犯糊涂似的&#xff0c;B題越理越亂&#xff0c;導致比賽結束&#xff0c;還在想著題&#xff0c;徹夜難眠&#xff01; A.Submission …

Apifox 7 月更新|通過 AI 命名參數及檢測接口規范、在線文檔支持自定義 CSS 和 JavaScript、鑒權能力升級

Apifox 新版本上線啦&#xff01; 看看本次版本更新主要涵蓋的重點內容&#xff0c;有沒有你所關注的功能特性&#xff1a; AI 助力接口設計 通過 AI 為參數命名 支持讓 AI 對接口進行規范性檢測 在線文檔功能增強 在線文檔支持自定義 CSS 和 JavaScript 目錄支持設置展示…

Node.js以及異步編程

什么是服務器&#xff1f;我們知道客戶端通過訪問服務器&#xff0c;然后服務器去操作數據庫把我們想要的數據拿過來給客戶端。比如服務器就是餐廳的服務員&#xff0c;數據庫就是廚房&#xff0c;客戶端就是我們的顧客。首先我們點菜&#xff0c;服務器告訴廚師做飯&#xff0…