现象
win7下,OCR服务 tesseract-ocr 运行3个小时以上时,稳定出现CPU过高。但其实此时并没有请求,也就是说服务本身没什么负载
jvisualvm观察
可以看到 GC 非常是频繁,推测是GC导致 CPU高
jmap分析
查看整个JVM内存状态
jmap -heap [pid]
要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起查看JVM堆中对象详细占用情况
jmap -histo [pid]导出整个JVM 中内存信息
jmap -dump:format=b,file=文件名 [pid]jhat是sun 1.6及以上版本中自带的一个用于分析JVM 堆DUMP 文件的工具,基于此工具可分析JVM HEAP 中对象的内存占用情况
jhat -J-Xmx1024M [file]
执行后等待console 中输入start HTTP server on port 7000 即可使用浏览器访问 IP:7000eclipse Memory Analyzer
Eclipse 提供的一个用于分析JVM 堆Dump文件的插件。借助这个插件可查看对象的内存占用状况,引用关系,分析内存泄露等。
http://www.eclipse.org/mat/
1 | jmap -histo:live 7304 > aaaa.log |
可以看到是一个 Collection 占用内存高
1 | jmap -dump:format=b,file=dumpocr.dump 16800 |
arthas分析
此时有观测到 是 两个线程各占50%的CPU,并没有GC线程,所以根源是 这两个线程导致 CPU高,而不是 GC导致的。
1 | "http-nio-16080-BlockPoller" Id=17 cpuUsage=50% RUNNABLE |
查看tomcat源码
NioEndpoint$Poller.run(NioEndpoint.java:708)
1 |
|
然后调用 keyCount = selector.select(selectorTimeout);
结果跟踪到了 jdk 中的调用,赶脚碰上了jdk nio selector空轮询导致cpu 100%问题
C:/Program Files/Java/jdk1.8.0_65/jre/lib/rt.jar!/sun/nio/ch/SelectorImpl.class
1 | private int lockAndDoSelect(long var1) throws IOException { |
跟踪到了native方法,再看就需要找到c的实现去看
抬头看看网友
https://stackoverflow.com/questions/36284833/spring-boot-application-starts-using-all-cpu
优化tomcat
使用NIO2
1 | package com.jzsec.tesseractocr.config; |
后续观察
持续运行一条后,没有再复现, 也不再有 http-nio-16080-BlockPoller
和 http-nio-16080-ClientPoller
线程