背景:

某一天系统出现了请求超时,然后通过日志查看,程序执行到某一个位置,直接停下来来了,或者说所有的线程的执行都停下来了。而且是该时间段,请求处理变慢。排查相关的服务,并没有出现死锁,异常,内存不足的情况,并且不是特定的接口超时,而且超时的时间也比较散乱。于是有同事提出来有没有可能系统正在做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…