写点什么

金融福尔摩斯修炼册 -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:041266

评论

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

大数据知识专栏 - MapReduce入门

小马哥

Java 大数据 hadoop mapreduce 七日更

杂谈

.

28天写作

Kubernetes概念篇:基本概念和术语

xcbeyond

Kubernetes 容器 pod 28天写作 Kubernetes从入门到精通

来不及解释!Linux常用命令大全,先收藏再说

华为云开发者联盟

Linux 编程 命令行 命令

古有诸葛亮八卦阵阻敌,今有iptables护网安

华为云开发者联盟

安全 防火墙 网络 iptables 数据包

自动驾驶和疫苗的相似之处——浅谈自动驾驶基本架构(28天写作 Day7/28)

mtfelix

自动驾驶 28天写作

想做出好决定,让头脑来次时空旅行吧!

Justin

思维模型 决策 28天写作

乐观主义

三只猫

28天写作

28天瞎写的第二百一八天:搬机房的故事

树上

28天写作

建立与孩子沟通的桥梁-从一个家庭会议开始

Ian哥

28天写作

第十三周课后练习

晴空万里

架构师训练营第2期

聚焦目标,团队工作不再一盘散沙(中)

一笑

管理 敏捷 目标管理 目标追踪 28天写作

『CDN』让你的网站访问起来更加柔顺丝滑

古时的风筝

CDN

读书笔记:《激荡三十年》上

lidaobing

28天写作 激荡三十年

Soul网关实践 01|把项目跑起来

哼干嘛

Java 探索与实践 API网关 Soul网关

解决div里面img图片下方有空白的问题

德育处主任

CSS html html5 大前端 28天写作

遇到代码缺陷不要慌,马上教你快速检测和修复

华为云开发者联盟

代码 bug 缺陷检测 代码缺陷

自动量化搬砖套利交易机器人系统软件APP开发

系统开发

生产者与消费者模式,数组阻塞队列(ArrayBlockingQueue)

李尚智

Java 学习 架构 并发编程

视频号第一周总结 | 视频号 28 天 (08)

赵新龙

28天写作

幻想着,直到大厦崩塌「幻想短篇 7/28」

道伟

28天写作

HDFS SHELL 详解(8)

罗小龙

hadoop 28天写作 hdfs shell

同事试用期没过就被劝退,我比他还难受

熊斌

职场 成长笔记 28天写作 职场新人

面试官:你真的了解Redis分布式锁吗?

鄙人薛某

redis 分布式锁 线程安全 RedLock

2021年,这是以太坊的发展方向?

李忠良

28天写作

关心群众生活,注意工作方法 Jan 15, 2021

王泰

28天写作

架构师训练营第十三周作业

李日盛

PageRank

Spring Boot如何动态修改日志级别

万里无云

Spring Boot actuator 日志级别

Spring Boot 集成 Swagger2 展现在线接口文档

武哥聊编程

Java springboot SpringBoot 2 swagger 28天写作

重学JS | Class

梁龙先森

大前端 编程语言 28天写作

万字多图 | UML 入门指南

白色蜗牛

Java 程序员 后端 架构设计 UML

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