写点什么

金融福尔摩斯修炼册 -FULL GC 篇

  • 2020-03-22
  • 本文字数:1801 字

    阅读完需:约 6 分钟

金融福尔摩斯修炼册-FULL GC篇

报警

上周四微信上收到智能告警,某应用出现 full gc 频繁问题,初步观察了下 sgm 和线上机器情况,定位问题。每次告警都是对我们每个金融消防员的考验:如履薄冰,胆战心惊。


立案调查

  • 分析依据:发生 fullGC 的最常见情况是老年代或者永久代空间不足时。

  • 现场分析:通过 SGM 查看老年代和永久代的空间占比剩余空间还有一定比例,不至于发生 fullGC,发生原因最后分析。



另外 sgm 上看了下 jvm 监控,发现堆内存从 14 号上午窜上去后再没下来过,下面这个图很容易定位是发生了内存泄漏,以下的思路就顺着定位内存泄漏的程序进行



  • 排查:看了下 mapi 代码提交记录,近期无上线,初步排除新上线代码问题。



在 sure 上使用 jmap 命令,发现 char 占据大量内存,怀疑存在大字符串。



周五找运维下了一份详细的 dump 文件,使用亮哥之前分享过的 IBMHeapAnalyzer 工具,分析发现问题可能出在 EnterRealNameApplyUploadImgReqModel 类里,这个类是用于实名申请时图片上传接口的入参实体类,里面包含了图片的 base64 的 string 串,占用较大空间。



排查 mapi 底层 biz 系统,查看 EnterRealNameApplyUploadImgReqModel 对应的实现类,发现 biz 中有对图片大小进行限制,最大为 2M,但是 mapi 无限制,怀疑可能为此接口中上传图片过大。


经磊哥点拨,发现 sdk 中对 base 串做了加密,并在 mapi 中做了解密处理,加解密工具为静态(static)工具方法,可能导致内存泄漏。



定位到问题后,再使用亮哥推荐的 visualVM 插件,在本地启了 mapi 应用,在 sdk 写了个死循环去调图片上传接口,并故意将照片设置为 3M,同时在 idea 的 VM Option 中 JVM 内存调至 300M,此时效果如下:



可以很清楚的发现,old 区增长速度特别快,同时 gc 次数频繁,并且无法有效的降低 old 区占用,old 区整体呈现递增趋势,很容易发生内存溢出,经过之前的定位流程,猜测为图片本身较大,在亚当区无法容纳该对象时,直接塞到 old 区,同时加解密方法为静态方法,被持续引用,导致无法进行垃圾回收,导致 old 区持续递增。

定案

处理方案


  • 生产服务器的内存为 8G,将堆内存从 2G 扩到 4G

  • 图片上传接口不在走通用加解密流程,在 sdk、mapi 单独为其封装了一套特殊的加解密流程,base64 串不进行加密,直接做拼接处理,其余参数做加解密。处理后效果如下:



处理后可以很明显的发现无论是 Old Gen 区的递增速度还是 gc 次数相较于之前发生了很大的变化,趋于正常。

案中案-CPU 分析

以上过程其实问题已经得到解决,但发现频繁报 fullgc 的机器,cpu 一直占用在 10%以上,怀着打破砂锅问到底的态度对 cup 的问题也进行了下分析:


1、通过 top 命令查看占用 cpu 过高的进程



可以看到占用 cpu 的进程 PID 为 7975


2、通过命令查找到占用 cpu 最高的线程


命令:top -H -p [进程id] top –H –p 7975



3、将线程号转化为 16 进制(jstack 线程堆栈中使用的 16 进制)


printf "%x\n" [线程id]



4、 查找线程号对应的线程


执行: jstack [进程id] |grep -A 10 [线程id的16进制]



由上图可以看到,一直在占用 CPU 的线程是 CMS 垃圾回收线程,由于堆内存占用过高程序又不释放,垃圾回收线程一直在尝试回收内存导致 cpu 过高。

并案分析-垃圾回收原因

上面再分析触发垃圾回收的时候留了一个小尾巴,为什么老年代和永久代占用不高的时候频繁的发生了 full gc 呢。由于此应用使用的是 jdk1.6,垃圾回收器使用的是 CMS,它是基于“标记–清除”算法实现的,特点是在收集结束的时候会有大量的空间碎片产生。空间碎片太多的时候,将会给大对象的分配带来很大的麻烦,往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象的,只能提前触发 full gc。如果 jdk 调整为 1.7u4 及以上即可使用 G1 垃圾回收算法不会产生大量的空间碎片。

结案总结

JVM 问题一般不是很容易遇到,程序有 bug 或者并发量大的时候均可能导致 jvm 异常,通过以上问题的分析过程及以往的经验简单总结下排查 jvm 问题的一般思路:


  • 查看 jvm 内存和机器 CPU 情况

  • 内存占用过高,可能是发生内存泄漏,需要导出 dump 文件借助 mat 或者是 IBM HeapAnalyze 来分析内存中哪些对象占比比较高,那些实例较多的对象需要重点分析

  • cpu 占用过高时可以通过步骤 4 的分析定位到具体的线程,程序编码中用到多线程的地方一定要给线程起个有意义的名字不要用默认的名字,这样出问题时方便定位。


上面只是个大概的流程,具体问题还需具体分析,重点还是需要 掌握 jvm 原理并灵活应用


2020-03-22 21:04759

评论

发布
暂无评论
发现更多内容

小厂逆袭美团|5年经验|一二三面经,已拿offer|

Java架构追梦

Java 架构 面试 美团Offer

硬核!阿里内部这份《Java面试核心知识手册》在Github上已获赞高达89.7K!

Java架构之路

Java 程序员 架构 面试 编程语言

非科班毕业生,五面阿里:四轮技术面+HR一面已拿offer

码农之家

Java 编程 程序员 互联网 面试

入门物联网嵌入式才是关键!

cdhqyj

技术 编程语言 物联网 嵌入式 系统

博云入选2021爱分析·产业数字化厂商全景报告

BoCloud博云

云计算 云原生 PaaS 博云

云原生势不可挡,华为云GaussDB加速企业数字化转型

华为云开发者联盟

华为云 GaussDB

《采访彩食鲜 CTO 乔新亮:如何从一名程序员晋阶为CTO》(采访提纲)

石云升

28天写作 4月日更 调查采访能力考核

最全 MongoDB 基础教程

若尘

数据库 mongodb mongo

HikariCP-技术专题-配置介绍和使用

洛神灬殇

智慧城市:大数据运营中心 IOC —— Web GIS 地图应用

一只数据鲸鱼

WebGIS ioc 数据可视化 智慧城市 数据运营

重读《重构2》- 提炼变量

顿晓

重构 4月日更

HDFS的垃圾桶机制

五分钟学大数据

hadoop 4月日更

应对海量时序数据,华为云GaussDB(for Influx)有妙招

华为云开发者联盟

云原生 数字化转型 时序数据 华为云GaussDB

Android面试送分题:大厂经典高频面试题体系化集合,实战篇

欢喜学安卓

android 程序员 面试 移动开发

想来百万流量技术公众号发布文章吗? InfoQ 开放内容平台了!

xiaotan

InfoQ 的朋友们 热门活动

Modus串行链路系统电气特性:2线-Modus、4线-Modus、RS232-Modus和RS485-Modus的特性

不脱发的程序猿

通信协议 4月日更 Modus 串行链路 RS232、RS485

Modbus协议在串行链路上的实现

不脱发的程序猿

通信协议 物联网常用协议 4月日更 Modbus 串行通信

android热修复基本原理,15分钟的字节跳动视频面试,满满干货指导

欢喜学安卓

android 程序员 面试 移动开发

iOS--面试题:多线程

ios 面试 多线程

全球案例 | NTT:Atlassian 帮助我们重塑危机中的可能性

Atlassian

敏捷 团队协作 数字化转型 Atlassian Jira

「 留言参与 」—— InfoQ 写作平台【 1 周年盛典 】

InfoQ写作社区官方

1 周年盛典 热门活动

PHP自动加载原理

Sakura

4月日更

阿里巴巴云原生 etcd 服务集群管控优化实践

阿里巴巴云原生

容器 运维 云原生 k8s 存储

想来百万流量技术公众号发布文章吗? InfoQ 开放内容平台了!

InfoQ写作社区官方

热门活动

1小时破千万点击量!阿里巴巴首发:Java核心框架指导手册

Java架构追梦

Java 阿里巴巴 架构 面试 核心框架

Flume高阶自定义组件

大数据技术指南

大数据 flume 4月日更

APM-技术专题-监控系统选型

洛神灬殇

APM 监控

JVM-技术专题-方法区中常量池分析

洛神灬殇

JVM 常量池

第一篇测试

童童

架构训练营

LeetCode题解:剑指 Offer 49. 丑数,三指针,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

7年Java经验|面20+家公司|已拿16个offer|面经总结|

Java架构追梦

Java 架构 面试 20+大厂面经

金融福尔摩斯修炼册-FULL GC篇_文化 & 方法_京东数字科技产业AI中心_InfoQ精选文章