一起SQL引发OOM的解决思路与过程(转载)
在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的解决思路与过程(转载)的更多相关文章
- 【OOM】解决思路
一.什么是OOM? OOM就是outOfMemory,内存溢出!可能是每一个java人员都能遇到的问题!原因是堆中有太多的存活对象(GC-ROOT可达),占满了堆空间. 二.怎么解决? 1.拿到内存溢 ...
- MySQL在并发场景下的问题及解决思路
目录 1.背景 2.表锁导致的慢查询的问题 3.线上修改表结构有哪些风险? 4.一个死锁问题的分析 5.锁等待问题的分析 6.小结 1.背景 对于数据库系统来说在多用户并发条件下提高并发性的同时又要保 ...
- 大数据小视角5:探究SSD写放大的成因与解决思路
笔者目前开发运维的存储系统的服务器都跑在SSD之上,目前单机服务器最大的SSD容量有4T之多.(公司好有钱,以前在实验室都只有机械硬盘用的~~)但SSD本身的特性与机械硬盘差距较大,虽然说在性能上有诸 ...
- java spring 等启动项目时的异常 或 程序异常的解决思路
今天搭建ssm项目的时候,因为pagehelper的一个jar包没有导入idea的web项目下的lib目录中,异常报错找不到pagehelper,这个问题在出异常的时候疯狂crash,让人心情十分不舒 ...
- DG日志不应用,GAP,主备切换解决思路与办法
环境ORACLE 10G OS WINDOWS 对于DG故障解决思路,DG日志切换不进行应用,DG出现GAP解决方法,DG主备库切换, 当DG出现故障时,第一时间检测alert日志,服务器OS日志,网 ...
- ADO.NET 使用DELETE语句批量删除操作,提示超时,删除失败,几种优化解决思路
起因是如此简单的一句sql 提示:Timeout 时间已到.在操作完成之前超时时间已过或服务器未响应. 提供几种解决思路: 1.检查WHERE条件中字段是否已建索引 2.检查是否被其他表引用,引用表外 ...
- C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路
C#不用union,而是有更好的方式实现 用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...
- java高并发解决思路
一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单,随着互联网业务的不断丰富,网站 ...
- ArcMap基于Oracle出现sde.instances_util.check_instance_table_conflicts:: ORA-00942:表或视图不存在/table or view doesnot exist解决思路
SDE环境:Oracle12C+ArcMap10.7+WinServer2012 出现问题情况: 1.SDE可以连接正常打开,但就是无法新建要素.导入要素等: 1)在根目录新建或导入要素,弹出提示: ...
随机推荐
- AOJ 2224 Save your cats (Kruskal)
题意:给出一个图,去除每条边的花费为边的长度,求用最少的花费去除部分边使得图中无圈. 思路:先将所有的边长加起来,然后减去最大生成树,即得出最小需要破坏的篱笆长度. #include <cstd ...
- 6-16 单词 uva10129
了解了欧拉回路和欧拉道路的性质 : 欧拉道路 最多只有两个奇点(不可能只有一个奇点) 并且当有两个奇点的时候 一个奇点入比出多一 一个奇点出比入多一 采用并查集查看是否连同 如果连 ...
- 6-10 下落的树叶 uva699
类似第九题 都是属于比较巧妙的题目 ! 用一个p数组来保存水平值 然后开始built 自然就会按照自左而右的顺序来读取!!!!!!这很重要 #include<bits/stdc++.h& ...
- Jquery框架1.选择器|效果图|属性、文档操作
1.JavaScript和jquery的对比 书写繁琐,代码量大 代码复杂 动画效果,很难实现.使用定时器 各种操作和处理 <!DOCTYPE html> <html lang=&q ...
- Linux —— 文件处理指令
- hystrix dashboard Unable to connect to Command Metric Stream解决办法
spring cloud 在初次使用 hystrix dashboard仪表盘的时候很容易出现hystrix dashboard Unable to connect to Command Metric ...
- RBF(径向基)神经网络
只要模型是一层一层的,并使用AD/BP算法,就能称作 BP神经网络.RBF 神经网络是其中一个特例.本文主要包括以下内容: 什么是径向基函数 RBF神经网络 RBF神经网络的学习问题 RBF神经网络与 ...
- Python3学习策略
自学Python要点 [来自:http://www.cnblogs.com/shsxt/p/9138950.html] 1.找一本浅显易懂,例程比较好的教程,从头到尾看下去. 不要看很多本,专注于一本 ...
- 潭州课堂25班:Ph201805201 爬虫基础 第九课 图像处理- PIL (课堂笔记)
Python图像处理-Pillow 简介 Python传统的图像处理库PIL(Python Imaging Library ),可以说基本上是Python处理图像的标准库,功能强大,使用简单. 但是由 ...
- Android工程运用阿里freeline10秒快速编译分享
git地址:https://github.com/alibaba/freeline 目前已经更新到0.6.0版本. 原来编译一次需要几分钟甚至几十分钟的android工程,运用freeline,1分钟 ...