JVM GC排查-JFR
yuyutoo 2025-01-02 20:11 7 浏览 0 评论
现象:
2024-09-12日发现某api服务GC告警明显增多
从告警上看,不仅GC次数有明显变多,更严重的是GC耗时很长,并且都是FullGC。
分析:
从告警上看,现象就是FullGC,先找一台机器(xx.xx.13.141)看看,在15:37和16:06分别有一次FullGC告警,看一下15:37的GC日志,确实发生了一次1.05s的FullGC
为什么会发生FullGC?一定是Old区内存都不够了,继续查看这次GC之前的日志(如下图),可以看到在Concurrent Cycles期间因为 humongous object的原因内存一直在涨,最终内存不足,导致FullGC。
继续查看这个时间点早一点的日志(下图)也能发现Concurrent Cycles也是因为humongous object分配导致。
因为G1的MixGC不会一次回收所有垃圾,而是会进行多次MixGC回收垃圾直到垃圾占比小于阈值(5%),如果某个时间段大对象分配频繁,就会发生MixGC跟不上分配节奏导致内存耗尽。
我们初步判断是因为大对象导致本次FullGC,dump内存看看大对象是什么?(RegionSize=2M,超过1M就是大对象)
从图上可以看出大对象基本分为两类:
第一类:
通过RequestMapping OkHttpClient关键词能搜到对应代码如下,就是一个http请求的拦截器打印日志
第二类:
看起来像Json,仔细看又不太像,因为这个字符串内有class的名称,一般json是没有className的,但是我们仍然基本能确定是跟Customer对象相关的。
我们现在已经确定了这些大对象都是 byte[], char[] 数组,但是怎么确定这些对象是因为哪行代码分配的呢?我们可以关闭日志打印,但是治标不治本,必须弄清楚这些大对象是否合理,如果不知道相关的代码我们没办法进一步排查和修复。
这里给出3种可以尝试的方式:
- 关键词搜代码:通过字符串内的特殊片段结合项目的业务去搜索和猜测相关代码,如果对项目的业务熟悉这种方式也很快能找到对应代码。
- dragonwell:是alibaba的一款JVM,这个JVM有一个增强的功能,对于基本数据类型的大数组分配,可以打印分配的堆栈,这样我们能准确的找到对应的代码。见 阿里巴巴Dragonwell8用户指南
- 通过JFR观察 outside 的TLAB分配记录
知识加油站:什么是TLAB?
我们知道堆内存是所有线程共享的,如果在堆上分配内存需要加锁。
为了提高性能,JVM会给每个线程单独分配一块自己的内存,这块内存就叫TLAB,线程分配对象时用自己的TLAB不需要加锁,当TLAB不够时,去堆再申请一块TLAB(要加锁)。
假设下面的场景,TLAB=100kb,已经使用90kb,如果要分配对象11kb,那么这时候怎么办?
很明显TLAB剩下的10kb不足以分配给11kb的对象,如果重新申请一个新的TLAB,那么就会导致10kb的空间浪费,为了平衡性能和空间浪费,JVM有一个TLAB最大浪费阈值(refill waste),10kb > refill waste就不会申请新的TLAB,而是11kb的对象直接在堆上分配,如果 10kb < refill waste,那么就会申请一块新的TLAB,10kb就浪费掉。
在JFR中可以持续观察TLAB的分配情况,Allocation in new TLAB表示在TLAB中分配,Allocation outside TLAB表示在TLAB外分配。
JFR如何使用?大家自行搜索
因为我们要找的对象是大对象,我们知道G1中大对象是在H区直接分配的,不可能使用TLAB,因此我们通过JFR查看Allocation outside TLAB事件大概就能知道大对象分配时的堆栈了。
先使用jcms命令收集JFR信息:maxage:保留多长时间的,maxsize:文件大小
jcmd pid JFR.start name=1.jfr maxage=1h maxsize=400MB
使用JDK Mission Control工具(JDK自带)打开jfr文件,打开事件浏览器,找到Allocation outside TLAB,选中一个大对象查看堆栈
具体的堆栈如下:
简单梳理一下调用链路:
ShopCloseController.checkCloseShop
-> StockService.getStock
-> StockService.removeVirtualGoods
-> PssService.getVirtualGoods()
-> ApiResponse com.sun.proxy.$Proxy369.getChannelMihomeGoodsMap(Integer)
-> 日志打印
对应的源代码如下:
也就是说 getChannelMihomeGoodsMap 方法返回值太大了,我们自定义的OkHttp拦截器打印日志就造成了大对象。
拿一个具体的大字符串看看长什么样:看起来是这个接口返回了所有渠道的所有sku信息,这个字符串非常大,另外在打印日志时底层的StringBuilder又扩容导致最后的char[]非常巨大。
实际上我们并不需要所有渠道的sku,只需要一个渠道的sku即可,因此后续要替换接口。
对于第二种1M左右的大对象,从堆栈上很容易看到是 CustomerController.getDetail(long, int) 方法查了缓存,缓存查出来的就是byte[](后怕:redis缓存在么大的key,也不怕把redis搞死)
通过源码也能看到,和上面的堆栈一致。
也就是说Customer对象序列化的byte[]数组太大了,虽然下图的字符串不完整,但是我们也能大概猜到是因为Customer的address太多导致,从图中能看到这个用户的id,
数据库查一下这个用户的地址有1501个,确实是地址太多了。
实际上从JFR上看,大对象不仅仅是上面这两种,还有因 InvoiceController.getList 底层返回数据多导致的大对象和 BranchCompanyController.list 缓存大导致的大对象,这里就不一一分析了。
总结
整体思路:
(1)为什么会GC?通过gc日志发现是大对象频繁分配导致
(2)大对象是什么?通过jmap dump内存后查看发现是日志打印的string等
(3)怎么修复?需要确定大对象从哪分配
(4)大对象在哪分配?通过JFR查看大对象分配时的堆栈,找到对应代码
(5)怎么修复?接口返回的数据减少不必要的数据
实际上从今年开始,我主导组内所有项目的GC治理开始,就发现了大对象是一个普遍现象,根本原因有二:
- 协议缺陷:服务之间调用使用http协议,参数和返回值都是string,一旦某些接口数据量大,必然会导致大的string对象,从现象来看都是某个对象有一些集合字段,集合太大,json序列化后的string就很大,二进制的序列化就不会有这个问题。
- 意思薄弱:开发人员在性能方面的意识非常薄弱,只管实现功能,至于性能怎么样压根不关心,以至于今年我在做GC分享的时候,有个leader问我你gc耗时30ms,我服务gc耗时1s还不是照样跑得好好的这样的问题。另外对于批量接口压根就不做数量的限制,基本都是全量数据直接扔出去。
相关推荐
- 墨尔本一华裔男子与亚裔男子分别失踪数日 警方寻人
-
中新网5月15日电据澳洲新快网报道,据澳大利亚维州警察局网站消息,22岁的华裔男子邓跃(Yue‘Peter’Deng,音译)失踪已6天,维州警方于当地时间13日发布寻人通告,寻求公众协助寻找邓跃。华...
- 网络交友须谨慎!美国犹他州一男子因涉嫌杀害女网友被捕
-
伊森·洪克斯克(图源网络,侵删)据美国广播公司(ABC)25日报道,美国犹他州一名男子于24日因涉嫌谋杀被捕。警方表示,这名男子主动告知警局,称其杀害了一名在网络交友软件上认识的25岁女子。雷顿警...
- 一课译词:来龙去脉(来龙去脉 的意思解释)
-
Mountainranges[Photo/SIPA]“来龙去脉”,汉语成语,本指山脉的走势和去向,现比喻一件事的前因后果(causeandeffectofanevent),可以翻译为“i...
- 高考重要考点:range(range高考用法)
-
range可以用作动词,也可以用作名词,含义特别多,在阅读理解中出现的频率很高,还经常作为完形填空的选项,而且在作文中使用是非常好的高级词汇。...
- C++20 Ranges:现代范围操作(现代c++白皮书)
-
1.引言:C++20Ranges库简介C++20引入的Ranges库是C++标准库的重要更新,旨在提供更现代化、表达力更强的方式来处理数据序列(范围,range)。Ranges库基于...
- 学习VBA,报表做到飞 第二章 数组 2.4 Filter函数
-
第二章数组2.4Filter函数Filter函数功能与autofilter函数类似,它对一个一维数组进行筛选,返回一个从0开始的数组。...
- VBA学习笔记:数组:数组相关函数—Split,Join
-
Split拆分字符串函数,语法Split(expression,字符,Limit,compare),第1参数为必写,后面3个参数都是可选项。Expression为需要拆分的数据,“字符”就是以哪个字...
- VBA如何自定义序列,学会这些方法,让你工作更轻松
-
No.1在Excel中,自定义序列是一种快速填表机制,如何有效地利用这个方法,可以大大增加工作效率。通常在操作工作表的时候,可能会输入一些很有序的序列,如果一一录入就显得十分笨拙。Excel给出了一种...
- Excel VBA入门教程1.3 数组基础(vba数组详解)
-
1.3数组使用数组和对象时,也要声明,这里说下数组的声明:'确定范围的数组,可以存储b-a+1个数,a、b为整数Dim数组名称(aTob)As数据类型Dimarr...
- 远程网络调试工具百宝箱-MobaXterm
-
MobaXterm是一个功能强大的远程网络工具百宝箱,它将所有重要的远程网络工具(SSH、Telnet、X11、RDP、VNC、FTP、MOSH、Serial等)和Unix命令(bash、ls、cat...
- AREX:携程新一代自动化回归测试工具的设计与实现
-
一、背景随着携程机票BU业务规模的不断提高,业务系统日趋复杂,各种问题和挑战也随之而来。对于研发测试团队,面临着各种效能困境,包括业务复杂度高、数据构造工作量大、回归测试全量回归、沟通成本高、测试用例...
- Windows、Android、IOS、Web自动化工具选择策略
-
Windows平台中应用UI自动化测试解决方案AutoIT是开源工具,该工具识别windows的标准控件效果不错,但是当它遇到应用中非标准控件定义的UI元素时往往就无能为力了,这个时候选择silkte...
- python自动化工具:pywinauto(python快速上手 自动化)
-
简介Pywinauto是完全由Python构建的一个模块,可以用于自动化Windows上的GUI应用程序。同时,它支持鼠标、键盘操作,在元素控件树较复杂的界面,可以辅助我们完成自动化操作。我在...
- 时下最火的 Airtest 如何测试手机 APP?
-
引言Airtest是网易出品的一款基于图像识别的自动化测试工具,主要应用在手机APP和游戏的测试。一旦使用了这个工具进行APP的自动化,你就会发现自动化测试原来是如此简单!!连接手机要进行...
- 【推荐】7个最强Appium替代工具,移动App自动化测试必备!
-
在移动应用开发日益火爆的今天,自动化测试成为了确保应用质量和用户体验的关键环节。Appium作为一款广泛应用的移动应用自动化测试工具,为测试人员所熟知。然而,在不同的测试场景和需求下,还有许多其他优...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)