在TOMCAT WEB程序的运行过程中,突然触发了内存溢出错误,检查Tomcat的localhost日志,找到如下信息:

java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:242)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
at java.util.ArrayList.add(ArrayList.java:440)
at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:3442)
……
at com.yiifaa.indicator.impl.HoleIndicatorServiceImpl.expireHoles(HoleIndicatorServiceImpl.java:191)
at com.yiifaa.indicator.controller.HoleIndicatorController.expireHoles(HoleIndicatorController.java:69)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

按照提示,找到代码进行检阅:

Map<String, Object> params = Maps.newHashMap();
String sql = sqlCache.get("expireHoles");
// 这里就是191行
List<Map<String, Object>> results = this.jdbcTemplate.queryForList(sql, params);
  • 1
  • 2
  • 3
  • 4

看了好几遍,没有发现明显的异常,既没有全局变量,也没有属性变量,没理由出现内存溢出,更重要的是,按照以往的经验,SQL应该没有这么大的爆炸力,而且难以确定的是,到底是该方法引发了OOM异常,还是碰巧就遇到了内存的瓶颈,从而导致内存异常,所以需要进一步判断。

刷新页面,调用应用程序接口,同时使用jstat监测JVM内存使用,如下:

# 首先获取程序ID
jps -l
# 然后根据程序ID获取其JVM内存使用信息
# 10代表时间间隔,毫秒
jstat -gcutil 47279 10
  • 1
  • 2
  • 3
  • 4
  • 5

执行jstat命令后,发现如表1的现象:

S0 S1 E(年轻代占比) O(老年代占比) P(永久代占比)
不变 持续增长 持续增长 持续增长 不变

增长的顺序依次是E(年轻代占比)增长到100%,然后S1增长到100%,然后O(老年代占比)增长到100%,最后触发full gc(全局垃圾回收),并且在内存变化的这段时间,并没有进行任何操作,连接数量也在比较小的范围。

#   统计HTTP连接的活动线程
jstack 47279|grep http-bio-8080-exec|grep runnable|wc -l
# 统计HTTP连接数量
netstat -nat|grep -i '8080'|wc -l
  • 1
  • 2
  • 3
  • 4

上述两个命令相互论证,证明HTTP连接是正常的,继续用jstack进行诊断,发现很多HTTP线程处于“WAITED”状态,这说明都是处于连接池中,等待被激活,依旧正常。

继续推测,内存的增长必然伴随对象数量的增加,于是采用jmap进行诊断,如下:

jmap -histo 47279|less 
  • 1

持续多次运行此命令,发现有个对象数量以及增长速度都不正常,如下:

1716115  41187603  com.mysql.jdbc.ByteArrayRow
  • 1

难道真是数据库连接的问题?突然想到,消耗内存较多的代码一定是运行中的线程,于是用jstack获取到的信息依次诊断线程,发现真有个数据库线程不正常,如下:

http-bio-8080-exec-89" daemon prio=10 tid=0x00007f039c09f800 nid=0xbcd1 runnable [0x00007f05350cc000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
……
at com.yiifaa.sec.indicator.impl.HoleIndicatorServiceImpl.expireHoles(HoleIndicatorServiceImpl.java:191)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

发现程序依旧卡在HoleIndicatorServiceImpl类的191行,最后诊断SQL语句,发现少了一个括号,导致or语句连接数量增长极快,从而是数据量达到了10的22次方,最后引发了如此大的执行灾难。

继续细化分析下去,因为返回结果是个List容器,所以随着游标的滑动,导致数据集不断增长,从而使得“com.mysql.jdbc.ByteArrayRow”对象数量暴增,最后导致内存溢出,结合内存的增长趋势,可以明显看出,当方法内部的对象增大到一定程度时,将会直接进入幸存代(S1),甚至是老年代。

总结

从内存的增加现象看: 
1. 只要对象足够大,完全有可能直接进入老年代,即使实在局部方法内; 
2. 局部方法也可能会导致内存溢出;

从诊断过程看,相关工具的作用如下: 
1. 用jps获取jvm进程ID; 
2. 用jstat确认GC内存消耗速度; 
3. 用jmap确认对象的增长速度与耗费空间; 
4. 用jstack确认错误代码的位置。

从SQL的教训看: 
1. 在多表连接时,请仔细检查连接语句; 
2. 万无一失的做法,请限定抓取数据的数量,例如100条,如“limit 0, 100”。

原文地址i:https://blog.csdn.net/yiifaa/article/details/78648358

一起SQL引发OOM的解决思路与过程(转载)的更多相关文章

  1. 【OOM】解决思路

    一.什么是OOM? OOM就是outOfMemory,内存溢出!可能是每一个java人员都能遇到的问题!原因是堆中有太多的存活对象(GC-ROOT可达),占满了堆空间. 二.怎么解决? 1.拿到内存溢 ...

  2. MySQL在并发场景下的问题及解决思路

    目录 1.背景 2.表锁导致的慢查询的问题 3.线上修改表结构有哪些风险? 4.一个死锁问题的分析 5.锁等待问题的分析 6.小结 1.背景 对于数据库系统来说在多用户并发条件下提高并发性的同时又要保 ...

  3. 大数据小视角5:探究SSD写放大的成因与解决思路

    笔者目前开发运维的存储系统的服务器都跑在SSD之上,目前单机服务器最大的SSD容量有4T之多.(公司好有钱,以前在实验室都只有机械硬盘用的~~)但SSD本身的特性与机械硬盘差距较大,虽然说在性能上有诸 ...

  4. java spring 等启动项目时的异常 或 程序异常的解决思路

    今天搭建ssm项目的时候,因为pagehelper的一个jar包没有导入idea的web项目下的lib目录中,异常报错找不到pagehelper,这个问题在出异常的时候疯狂crash,让人心情十分不舒 ...

  5. DG日志不应用,GAP,主备切换解决思路与办法

    环境ORACLE 10G OS WINDOWS 对于DG故障解决思路,DG日志切换不进行应用,DG出现GAP解决方法,DG主备库切换, 当DG出现故障时,第一时间检测alert日志,服务器OS日志,网 ...

  6. ADO.NET 使用DELETE语句批量删除操作,提示超时,删除失败,几种优化解决思路

    起因是如此简单的一句sql 提示:Timeout 时间已到.在操作完成之前超时时间已过或服务器未响应. 提供几种解决思路: 1.检查WHERE条件中字段是否已建索引 2.检查是否被其他表引用,引用表外 ...

  7. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  8. java高并发解决思路

    一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单,随着互联网业务的不断丰富,网站 ...

  9. ArcMap基于Oracle出现sde.instances_util.check_instance_table_conflicts:: ORA-00942:表或视图不存在/table or view doesnot exist解决思路

    SDE环境:Oracle12C+ArcMap10.7+WinServer2012 出现问题情况: 1.SDE可以连接正常打开,但就是无法新建要素.导入要素等: 1)在根目录新建或导入要素,弹出提示: ...

随机推荐

  1. [转]oracle10客户端PL/SQL Developer如何连接远程服务器上的oracle数据库

    时间:2013年8月21日 前提条件:假设你已经安装好了oracle和PL/SQL Developer,知道远程服务器的IP和数据库端口,知道远程服务器上的oracle数据库名和密码 如何用PL/SQ ...

  2. openstack学习-nove控制节点部署(四)

    nove在openstack非常重要,主要负责创建虚拟机 nova计算服务 API :负责接收和响应外部请求.支持openstack API,EC2 API Cert:负责身份认证EC 2 Sched ...

  3. 解决python中遇到的乱码问题

    1. 解决中文乱码的一种可行方法 # -*- coding:utf-8 -*- from __future__ import unicode_literals import chardet def s ...

  4. WebPack 学习:从阮神的15个DEMO开始

    WebPack 是什么 官方就一句话,打包所有的资源. 从阮神的 15 DEOM入手 Webpack Github 地址 阮神GIT 按照 ReadME 操作 npm webpack-dev-serv ...

  5. CTFlearn Inj3ction Time --sql注入python多线程脚本练习

    0x00前言: 本题是国外的一个CTF平台的题目,题目不难,但学习了波多线程payload写法 先看题目描述,提示"union是个有用的命令",估计是用联合查询就能出答案的(因为前 ...

  6. vue 解决双向绑定中 父组件传值给子组件后 父组件值也跟着变化的问题

    说明: 近日开发中碰见一个很诡异的问题,  父组件动态的修改对象 data 中的值, 然后将这个对象 data 传给子组件, 子组件拿到后将 data 中的值 乘以 100 ,发现父组件中的值也跟着变 ...

  7. SQL RAISERROR 用法

    ) ), YOUR UNIQUEIDENTIFIER KEY) ,, @raiseErrorCode) RAISERROR ( N'This is message %s %d.', -- Messag ...

  8. supervisor 管理 celery

    安装supervisor [root@ipv6-api ~]# pip3 install  supervisor 生成配置文件 [root@ipv6-api ~]#echo_supervisord_c ...

  9. 从新安装SQLserver 过程中报错问题合集

    1.安装SQL SERVER2008 到安装支持文件就闪退? 分析:这个是由于安装目录没有删除干净导致的,我遗漏了一个文件夹:microsoft Management console文件夹没有删除的原 ...

  10. BZOJ.4298.[ONTAK2015]Bajtocja(Hash 启发式合并)

    题目链接 \(Description\) 给定\(d\)张无向图,每张图都有\(n\)个点.一开始,在任何一张图中都没有任何边. 接下来有\(m\)次操作,每次操作会给出\(a,b,k\),意为在第\ ...