由于cmd引发的血案
/ / 点击 / 阅读耗时 7 分钟前言
给教务处做一个工作量审核的web项目,前几天完成后部署在机房电脑上进行测试,但是测试的时候出现了Bug,会存在一个用户登录的时候,整个应用卡死,所有人都无法登陆,因为登陆模块是我写的,我当时就慌了(并不),然后赶紧去机房看看到底是啥情况
FixBug
其实我首先想到的就是网络或者数据库的问题,但是看了我控制台的输出,发现代码其实根本就还没到数据库层!所以先排除了数据库的问题
然后我就想会不会是GC的问题,然后我打开了 jvisualvm
,准备查看当前的堆占用和GC情况,但是他们之前重启了服务,现在是正常的,看不出来什么,所以我们需要复现这个Bug,结果我们几个人在哪里搞了半天死活复现不了😂
在经过我们一个小时多小时坚持不懈的尝试下,终于复现了!
页面hang住,所有人都无法登陆,后台也并没有任何的错误信息,然后我赶紧去看了下 jvisualvm
发现堆并没有任何变化,GC也并没有发生!而且更诡异的是其他的已经登陆的人是可以正常的操作的!只是卡住了登陆的人,所以GC的问题也排除了
在dump出线程快照后终于发现了问题所在
图中的这条线程卡在了 PrintStream.println()
上,而这个是我在Service打印的log信息,为什么会在这里卡住???这不科学啊,然后我看了 其他 tomcat的工作线程,发现还有好几个都是BLOCK
状态,都在等 [0x0000004df8afd000]
这把锁,这个锁被另一个tomcat的工作线程 http-bio-80-exec[2]
所持有,而且它并不是BLOCK
状态,而是 RUNNABLE
状态,这个线程正在执行 java.io.FileOutputStream.writeBytes()
方法,我们去看看println
的源码
/** |
可以看出在println方法确实是加了锁的,锁的对象就是当前的PrintStream实例对象,而占用这个锁的对象的线程则正在执行下面这个方法,是个本地方法我们看不到底层的细节
/** |
无奈,借助搜索引擎,果然查到了同样的问题
一个RUNNABLE状态的线程hang在了java.io.FileOutputStream.writeBytes方法上
当然原问题是来自StackOverflow
问题的根本原因:在CMD窗口点击了黑框之后,控制台就会被暂停
,进入编辑模式,之后向控制台的输入缓冲区会被很快填满,然后正在输出的线程就会hang住,但是正在输出的线程也并不会BLOCK
,状态仍然是RUNNABLE
所以就很诡异,也就是上面所描述的情况,当你这个时候在CMD状态下按一下回车或者其他的键释放console,退出编辑模式
这个线程又会继续往下执行,要解决这个问题可以调整cmd的设置,我这里其实无所谓,因为后面并不会在win上运行
至此问题就基本解决了(其实都不算问题),没想到还会被cmd给坑一把,不过增长了一点排查问题的能力也还是不错的😁
总结
最大的收获就是: 遇到bug不要先急着重启逃避问题,得面对它,因为有些bug完全就是偶然性的,一旦放过,要想复现可能会极其困难,这次还算运气好,最终复现了,不过当时如果他们保护了现场后面就不会花几个小时去复现问题(确实大家也都经验不太足),也算是吃一堑长一智了 hahaha ~~