【转】一次由过量线程引发的OOM排查
mac的话,还得进行下特殊处理:右键mat显示包内容,进入Contents->MacOS下面,会有一个MemoryAnalyzer的命令。
打开终端,进入此路径找到MemoryAnalyzer,运行 ./MemoryAnalyzer -data ./dump
最近,公司的系统老是出现定时任务延迟执行的情况,一开始以为是由于基本上在那个点,需要执行的任务过多,而执行线程只有一个引起的正常列队(用的是springtask的定时任务,默认配置的线程池中最大线程数量为1),但在一个月黑风高的夜晚,客户反应没有任何的产品上架,而且已经离定时上架任务执行的时间过去了1个多小时,感觉肯定是系统出现了不可描述的问题。(由于没带电脑回家,是第二天去公司做的调试,当时以手动上架的方式先解决燃眉之急)
第一步:查询了下完整的tomcat输出日志,发现了出现停顿的问题,就是OutOfMemoryError,如图:
第二步:发生停顿的时间是在15号23.00左右,刚好是执行产品上架的时间,然后继续往下看日志,发现日志输出的时间有问题:
第三步:所以可以推测,其实当时日志写入的时候,真正时间已经是16号00:21分,但由于以前阻塞的线程现在才开始继续活动,所以记录的还是他阻塞时候获得的时间;而且看default.log也能发现,15号23:00之后,就没有任何的日志输出,其实整个系统都已经处于挂起状态,所以联想到造成整个系统停止的原因应该是FullGC引起的,立马去看了下系统的gc情况(因为tomcat没有配gc日志输出,所以没法跟踪到当时的gc情况,只能看gc的总输出):
看到总共做了18111次的FullGC,停顿时间5627秒,超过一个半小时。。。(瑟瑟发抖)
第四步:用指令:jmap -heap pid ,查看当前的内存使用情况,发现内存还是很吃紧,说明问题其实还是存在的;
第五步:用指令: jmap -dump:format=b,file=fileName pid 获取下内存文件,然后下载到本地,再用eclipse的MAT内存分析工具进行分析,刚打开,就发现问题所在:
Thead线程对象竟然创建了226M,而系统运行的总内存也就512M,所以问题一定是在线程的创建上了,继续往下看,打开overview ——>Actions中的Histogram:看到是byte[]所占的内存最多,继续追踪byte[]的生成对象,
发现这2个所占的容量是最大的,继续点开,查看调用追踪,发现上面那个反射对象,应该是框架自身使用的原因,不是异常;
下面那个com.jcraft.jsch.Session经查代码,发现是连接sftp的一个session对象,而且他自身实现了RunAble接口,所以start之后,本身就是一个运行的线程,如果没有被正确关闭,就会运行停留代码里面设置的时间,所以在这期间,是不会被GC回收的;
继续看代码,发现确实是获取sftpChannel对象的方式有问题,如果在getChannel()方法中,发生异常,导致session已经启动,但返回的channel却是null,获取到的sftpChannel就是null的,也就是无法在后面进行关闭,只能等待他自己超时
所以针对上面的问题,给出的解决方案是,在getChannel()方法中,自己进行异常的捕获,如果发生异常,就立马进行session的关闭,且加大系统的内存到1G。
注:当时为了验证GC没有回收的原因是因为线程一直在运行造成的,所以还用指令:jstack pid
获取下了线程的运行状态文件,发现确实是4800多的sftpSession的连接线程,一直处于runable中,刚好能和内存中session对象个数进行对应。。。
【转】一次由过量线程引发的OOM排查的更多相关文章
- Asp.Net正在中止线程引发的问题
背景: Asp.Net做的一个同步程序,同步的方法是通过JQuery的Ajax调用,同步过程大概要执行20多分钟,程序部署到服务器后执行一段时间后就弹出执行失败的对话框,日志记录的错误信息是“正在中止 ...
- 【心得】asp.net 异常:正在中止线程 引发的问题
asp.net做的一个同步程序,同步的方法是通过JQuery的Ajax调用,同步过程所需要的时间大概有几个小时吧. 当在本机运行的时候,无论是debug模式还是release模式,都能正常运行. 发布 ...
- 记一次线上dubbo服务超时和线程池满问题排查
线上某dubbo服务A调用dubbo服务B的接口X方法,调用端A日志中出现了很多超时的情况,提供端B该接口X超时时间设置为60s: 查看提供端B的日志,报了很多线程池满的异常: Caused by: ...
- index_merge引发的死锁排查
概述 前几天排查了一个死锁问题,最开始百思不得其解,因为发生死锁的两个事务是单语句事务,语句类型相同(where属性列相同,仅值不同),而且语句都走了相同的索引,但最终确实发生了死锁.通过定位排查发现 ...
- 详解线程池的作用及Java中如何使用线程池
服务端应用程序(如数据库和 Web 服务器)需要处理来自客户端的高并发.耗时较短的请求任务,所以频繁的创建处理这些请求的所需要的线程就是一个非常消耗资源的操作.常规的方法是针对一个新的请求创建一个新线 ...
- InvokeRequired 线程间访问
zt: http://www.x2blog.cn/jinhong618/?tid=22389 问: f (this.InvokeRequired) { ...
- 线程——委托InvokeRequired和Invoke
C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...
- C#之Winform跨线程访问控件
C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...
- JVM运行时内存组成分为一些线程私
JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...
随机推荐
- mysql中date,datetime,timestamp数据类型区别
(1)date表示日期,其范围为1000-01-01到9999-12-31 (2)datetime表示日期时间,其范围是1000-01-01 00:00:00到9999-12-31 23:59:59 ...
- 一次对webshell的后门的查看
本文作者i春秋作家——非主流 昨天晚上突发奇想的想去看看github上面tennc的webshell收集项目中的shell有没有漏洞,比如未授权啊啥的,结果找半天都没找到...但是机缘巧合下,居然给我 ...
- Flask从入门到精通之跨站请求伪造保护
默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击.恶意网站把请求发送到被攻击者已登录的其他网站时就会引发CSRF ...
- PHP之旅6 php的类与面向对象
对于类与面向对象的问题其实刚开始不用非要弄懂原因,直接先这样用,用多了你就发现你会了.所以 学习面向对象就先去做.用的多了你就发现这个就是这样的. 对于类的理解,我自己的理解就是:有一个叫做类的东西里 ...
- 如何利用反射简化Servlet操作
如何利用反射简化Servlet操作 一.反射的实现 新建类BaseServlet,继承HttpServlet(不需要在web.xml文件中配置) 1.在doPost()方法中处理请求乱码,并调用d ...
- 实验三:分别用for、while和do-while循环语句以及递归方法计算n!,并输出算式
一.用for循环计算n! package for_package; import java.util.*;//导入含有输入类的包 public class for_class { /** * @par ...
- Opencv --- 图像像素遍历的各种方法
#include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/highgu ...
- javascript中创建对象的几种不同方法
javascript中创建对象的几种不同方法 方法一:最直白的方式:字面量模式创建 <script> var person={ name:"小明", age:20, s ...
- 剑指offer二十九之最小的K个数
一.题目 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 二.思路 详解代码. 三.代码 import java.util. ...
- 在Vue的webpack中结合runder函数
在Vue的webpack中结合runder函数 1.引入: <h1>下面是vue的内容:</h1> <div id="app"> <log ...