最近写了一个学习的小项目,使用到了socket编程,却发现了在不停启动时内存飙升至100%,且永不下降的问题,本文记录下排查的过程。
- https://docs.microsoft.com/zh-cn/sysinternals/downloads/process-explorer)。
选中java.exe鼠标邮件查看properties
可以看到线程ID号未6252、8352、6528的3个线程分别CPU消耗为24%以上,合起来刚好为CPU消耗的70%多;证明了为该Java项目导致的CPU飙升且常驻;
一般来说,CPU持续占比且不下降,几乎都是线程持续占用,或者死循环引起的。
- 使用jstack工具查看线程占用情况
- 使用JPS命令查看java进程PID
- 使用 jstack -l PID > f:/xxxx.stack (小写的L) 来生成线程堆栈信息
出现Unable to attach to 64-bit process
7508: Unable to attach to 64-bit process
The -F option can be used when the target process is not responding
因为当前环境的JVM版本与Java程序的JVM版本不一致,如果当前系统里有多个JDK或者JRE版本的话,就会出现此问题。笔者本机是共存了JDK8与JDK11,环境变量设置的8,而MiniCatStater程序启动用的11,直接cd到JDK11的bin目录下继续执行jstack命令
用文本编辑器打开 7508.stack 文件
上面咱们提到 6252、8352、6528 这三个线程号,选择6252转换为十六进制 0x186C 进行搜索
可以看到线程当前执行位置为 at com.kevin.minicat.server.RequestProcessor.run(RequestProcessor.java:33)
- 定位代码位置
可以看到,执行位置为循环体内 count = inputStream.available() 方法,百度一下~
因为网络通讯往往是间断性的,一串字节往往分几批进行发送。例如对方发来字节长度100的数据,本地程序调用available()方法有时得到0,有时得到50,有时能得到100,大多数情况下是100。这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。也许分3批到达,也许分两批,也许一次性到达。
所以为了避免获取数据错误,需要持续调用,等待输入流完全准备完成后再完成对流的读取。
- 加一个超时时间,如果等待超时,则直接关闭流。
- 使用Nio方式进行编程。效率更高,不会出问题。BIO阻塞容易异常。
Kevin Lee
文章链接:http://blog.ksisn.com/2020/12/27/%E7%AE%80%E8%AE%B0windows%E4%B8%8Bjava%E7%A8%8B%E5%BA%8Fcpu%E9%A3%99%E5%8D%87%E9%97%AE%E9%A2%98/
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0 协议。转载请注明出处!