JVM 频繁 FULL GC 快速排查整理
在分享此案例前,先聊聊哪些场景会导致频繁Full GC:
内存泄漏(代码有问题,对象引用没及时释放,导致对象不能及时回收)
死循环
大对象
程序执行了System.gc()
尤其是大对象,80%以上的情况就是他。 那么大对象从哪里来的:
【1】数据库(包括 Mysql和 Mongodb等 NOSql数据库),结果集太大;
【2】第三方接口传输的大对象;
【3】消息队列,消息太大;
根据多年一线互联网经验,绝大部分情况是数据库大结果集导致。好,现在我们开始介绍这次线上故障:
在没有任何发布的情况下,POP(point of purchase的缩写bai,意为“卖点广告”其主要商du业用途是刺激引导zhi消费和活跃dao卖场气氛)服务(接入第三方商家的服务)突然开始疯狂Full GC,观察堆内存监控没内存泄漏,回滚到前一版本,问题仍然存在,尴尬了!!!
按照常规做法,一般先用 jmap导出堆内存快照(jmap -dump:format=b,file=文件名 [pid]),然后用 mat等工具分析出什么对象占用了大量空间,再查看相关引用找到问题代码。为了进一步排查原因,我们在线上开启了 -XX:+HeapDumpBeforeFullGC在其中一台机子上开启了 -XX:HeapDumpBeforeFullGC,总体JVM参数如下:
1 -Xmx2g
2 -XX:+HeapDumpBeforeFullGC
3 -XX:HeapDumpPath=.
4 -Xloggc:gc.log
5 -XX:+PrintGC
6 -XX:+PrintGCDetails
7 -XX:+PrintGCDateStamps
8 -XX:+UseGCLogFileRotation
9 -XX:NumberOfGCLogFiles=10
10 -XX:GCLogFileSize=100m
11 -XX:HeapDumpOnOutOfMemoryError
注意:JVM 在执行 dump操作的时候是会发生 stop the word事件的,也就是说此时所有的用户线程都会暂停运行。为了在此期间也能对外正常提供服务,建议采用分布式部署,并采用合适的负载均衡算法
dump下来的文件大约 1.8g,用 jvisualvm查看,发现用 char[]类型的数据占用了41%内存,同时另外一个 JdbcSqlStat类型的数据占用了35%的内存,也就是说整个堆中几乎全是这两类数据。如下图:
查看char[]类型数据,发现几乎全是sql语句:
接下来查看char[]的引用情况:并对代码进行修改
这种方式定位问题周期会比较长,如果是关键服务,长时间不能定位解决问题,影响太大。
下面来看看我们的做法。先按照常规做法分析堆内存快照,与此同时另外的同学去查看数据库服务器网络IO监控,如果数据库服务器网络IO有明显上升,并且时间点吻合,基本可以确定是数据库大结果集导致了Full GC,赶紧找DBA快速定位大SQL(对DBA来说很简单,分分钟搞定,如果DBA不知道怎么定位,那他要被开除了,哈哈),定位到 SQL后再定位代码就非常简单了。按照这种办法,我们很快定位了问题。原来是一个接口必传的参数没传进来,也没加校验,导致 SQL语句 where后面少了两个条件,一次查几万条记录出来,真坑啊!这种方法是不是要快很多,哈哈,5分钟搞定。
当时的 DAO层是基于 Mybatis实现的,出问题的SQL语句如下:
1 <select id="selectOrders" resultType="com.***.Order" >
2 select * from user where 1=1
3 <if test=" orderID != null ">and order_id = #{orderID}</if >
4 <if test="userID !=null">and user_id=#{userID}</if >
5 <if test="startTime !=null">and create_time >= #{createTime}</if >
6 <if test="endTime !=null">and create_time <= #{userID}</if >
7 </select>
上面SQL语句意思是根据 orderID查一个订单,或者根据 userID查一个用户所有的订单,两个参数至少要传一个。但是两个参数都没传,只传了 startTime和 endTime。所以一次 Select就查出了几万条记录。所以我们在使用 Mybatis的时候一定要慎用 if test,一不小心就会带来灾难。后来我们将上面的SQL拆成了两个:
根据订单ID查询订单:
1 <select id="selectOrderByID" resultType="com.***.Order" >
2 select * from user where
3 order_id = #{orderID}
4 <if test="startTime !=null">and create_time >= #{createTime}</if >
5 <if test="endTime !=null">and create_time <= #{userID}</if >
6 </select>
根据 userID查询订单:
1 <select id="selectOrdersByUserID" resultType="com.***.Order" >
2 select * from user whereuser_id=#{userID}
3 <if test="startTime !=null">and create_time >= #{createTime}</if >
4 <if test="endTime !=null">and create_time <= #{userID}</if >
5 </select>
JVM 频繁 FULL GC 快速排查整理的更多相关文章
- 一次频繁Full GC问题排查过程分享
问题描述 应用收到频繁Full GC告警 问题排查 登录到对应机器上去,查看GC日志,发现YGC一分钟已经达到了15次,比Full GC还要频繁一些,其中Full GC平均10分钟超过了4次,如下图 ...
- java面试题之----JVM架构和GC垃圾回收机制详解
JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...
- 一次CMS GC问题排查过程(理解原理+读懂GC日志)
这个是之前处理过的一个线上问题,处理过程断断续续,经历了两周多的时间,中间各种尝试,总结如下.这篇文章分三部分: 1.问题的场景和处理过程:2.GC的一些理论东西:3.看懂GC的日志 先说一下问题吧 ...
- [转]一次CMS GC问题排查过程(理解原理+读懂GC日志)
这个是之前处理过的一个线上问题,处理过程断断续续,经历了两周多的时间,中间各种尝试,总结如下.这篇文章分三部分: 1.问题的场景和处理过程:2.GC的一些理论东西:3.看懂GC的日志 先说一下问题吧 ...
- 如何快速排查解决Android中的内存泄露问题
概述 内存泄露是Android开发中比较常见的问题,一旦发生会导致大量内存空间得不到释放,可用内存急剧减少,导致运行卡顿,部分功能不可用甚至引发应用crash.对于复杂度比较高.多人协同开发的项目来讲 ...
- JVM中的GC算法,JVM参数,垃圾收集器分类
一.在JVM中什么是垃圾?如何判断一个对象是否可被回收?哪些对象可以作为GC Roots的根 垃圾就是在内存中已经不再被使用到的空间就是垃圾. 1.引用计数法: 内部使用一个计数器,当有对象被引用+1 ...
- JVM虚拟机 与 GC 垃圾回收
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.JVM体系结构概述 1.JVM 与系统.硬件 JVM是运行在操作系统之上的,它与硬件没有直接的交 ...
- JVM专题3: GC 垃圾回收
合集目录 JVM专题3: GC 垃圾回收 什么是GC? 为什么要有 GC? Garbage Collection, 用于内存回收. 简述一下 Java 垃圾回收机制? 那些内存需要回收 虚拟机中程序计 ...
- JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)
引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法,而且几乎是一定会有,因为LZ相信高人们的能力. 那么分代搜集算法是怎么处理GC的呢? 对象分 ...
- JVM内存管理------GC简介
为何要了解GC策略与原理? 原因在上一章其实已经有所触及,就是因为在平时的工作和研究当中,不可避免的会遇到内存溢出与内存泄露的问题.如果对GC策略与原理不了解的情况下碰到了前面所说的问题,很多时候会让 ...
随机推荐
- Python 用exec来获取字符串所对应的字典
Python 用exec来获取字符串所对应的字典 Python exec 问题的提出 想要遍历两个结构相似的字典,但是不想采用字典内嵌套字典的方式,所以想要通过一个列表,该列表包含字典名称.也就是通过 ...
- npm start ERROR
npm start 遇到问题 Attempting to bind to HOST environment variable: x86_64-apple-darwin13.4.0 If this wa ...
- 写一些Linux文件夹操作的一些感悟。
rwx 权限 对目录的作用 读权限(r) 表示具有读取目录结构列表的权限,也就是说,可以看到目录中有哪些文件和子目录.一旦对目录拥有 r 权限,就可以在此目录下执行 ls 命令,查看目录中的内容. 写 ...
- Java基础Day7-值传递和引用传递
一.值传递 Java都是值传递. 值传递:是指在调用函数时,将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,就不会影响到实际参数. 值传递是对基本数据类型而言. 二.引用传递 引用传递 ...
- 面向对象1(Java)
什么是面向对象 面向对象编程(oop) 面向对象编程的本质是:以类的方式组织代码,以对象的组织(封装)数据 抽象 三大特征:封装.继承.多态 从认识论角度考虑是先有对象后有类.对象是具体的事物.类是抽 ...
- Linux目录结构说明与基本操作
Linux系统目录如下: 详细说明如下: Linux系统文件与目录的基本操作: 一.显示文件内容命令--cat.more.less.head.tail. 1.cat命令 该命令的主要功能是用来显示文件 ...
- 测试Lock锁
package com.company;import java.util.concurrent.locks.ReentrantLock;//测试Lock锁public class TestLock i ...
- iOS Unity 项目解析
本文旨在记录Unity 导出的iOS 项目笔记,另带接入SDK的终极方案,顺带对比Android 项目 1蓝色的目录 Data 这个就是项目的数据,每个项目不一样也就是这个目录不一样,是不是可以把这个 ...
- Lombok和MapStruct冲突
Lombok和MapStruct冲突导致无法生成正确的class文件. lombok自动生成getset等冗余代码. MapStruct对象copy.传统的BeanUtils.copy等利用的反射原理 ...
- nodejs res常用的返回方式
常用的返回方式有四种 res.json([status|body], [body]) 以json的形式返回数据res.render(view [, locals] [, callback]) 返回 ...