tomcat部署项目通过jstack发现大量的tomcat线程等待

tomcat部署项目通过jstack发现大量的tomcat线程处于等待状态:waiting on condition, 

最终的结果就是导致服务jvm内存越来越大,服务内存被用完!再也不响应http请求了,
请问是什么原因导致的?

"http-nio-80-exec-13" #116 daemon prio=5 os_prio=0 tid=0x00007fa604028000 nid=0x2a43 waiting on condition [0x00007fa5d42b4000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000dfa8eb18> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103)
	at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

"http-nio-80-exec-12" #115 daemon prio=5 os_prio=0 tid=0x00007fa5f8002800 nid=0x2a42 waiting on condition [0x00007fa5d453c000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000dfa8eb18> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103)
	at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)


我查了两天资料,说是http没有正常释放 导致的!然后我看了render方法的response只是flush,没有close,  请问是这个问题么?如果不是这个问题,请问会是什么问题!    

我的猜想: 导入execl导致的,但是poi解析完excel后close了, 而且stream也close了,但是经常会有解析完了的文件删除不掉! 但是这里问题不大,

另外一个问题是:使用单列模式,去数据库去一个唯一的code, 由于这里做了数据的查询和修改,我不知道这里会不会有影响。这个单例的方法还加了synchronized

还有个猜想:就是http的长链接,keep-alive, 但是我没办法连想起来。


评论区

JFinal

2019-10-17 21:26

异常信息不涉及 jfinal ,应该是与 jfinal 无关的

此外, render 中的 response 在早期的 jfinal 版本中是有 close() 的,通过查看 tomcat、jetty 源码可知,使用 close() 是没有必要的,并且会降低性能。 在 close() 掉以后如果后续还有数据输出则会抛出异常

因此,在 render 中 close() 不仅没有好处,反而很多坏处。 close() 不是你碰到的这个事的原因,不要往这个方向去想

既然是内存占用越来越大,通过 JDK 自带的 visual VM 查看一下内存占用情况,分分钟就可以定位解决问题

tuxming

2019-10-19 09:59

是 java.util.LinkedHashMap$Entry占用内存最多。 占了50%

JFinal

2019-10-19 15:01

@tuxming 已经定位到了 java.util.LinkedHashMap$Entry占用内存多, 进一步定位该 HashMap 是哪个地方创建的,问题自然就解决了

java.util.LinkedHashMap$Entry 这个不是根本原因,是表面原因

tuxming

2019-10-25 18:53

谢谢大佬!这个是用户量激增,而且用户都是大把的导入excel,导致mode对象突然增多导致的!增加了内存解决了,将来的话,可能需要考虑分布式了

JFinal

2019-10-25 19:01

@tuxming 内存占用突发性增大挺危险,因为 JVM 的垃圾回收本身就有延迟问题

想办法控制内存占用的速度小于回收的速度

tuxming

2019-10-25 19:50

代码里面控制吗?我看了几遍关键代码位置,发现没有太好的办法,都是正常调用!系统本身不复杂,只是使用的人多!

JFinal

2019-10-25 19:57

@tuxming 建立对象池,让对象用完以后可以回收,下次需要用的时候不用重新申请内存,而是从池里面取用

当然,池中的对象多少要控制好,不让无限制增长

tuxming

2019-10-25 20:00

好的,谢谢大佬,这块儿按你的思路想想办法。

tuxming

2020-01-11 19:09

解决了,excel导入问题, 用户不知道怎么做的excel,明明只有几行数据,但是系统却判定有100多万行数据,结果就是有那么5,6个用户同时上传这种excel就直接导致程序挂掉,目前没啥好的解决办法。

建议方法:
1,检测excel大小超过2M的excel的不让导入
2,引导客户做正确的表格