这次的内存溢出需要书接上回
上次堆内存过高的优化方案是:不将大对象传入线程中,而是在只传对象id,在线程中查出需要的对象后再到主线程赋值。在考虑到查询效率上,使用了多个线程分别查询额外属性,最后进行统一赋值。
优化后上线一周,有一天服务突然报错:org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: unable to create new native thread
意思就是不能再创建新的线程,导致服务直接挂掉。
问题原因知道了是因为线程开的太多,但为什么能导致服务关闭呢?
既然是线程的问题,那就要先用top -H查看服务器当前线程数
但服务已经挂掉了,在这里已经看不到开了多少线程
好在线上是两台服务,另一台虽然没挂,但线程数量肯定也很多,去另一台服务使用jstack pid > stack.log打印服务的线程日志
发现全是WAITING状态的线程 ,且是LinkedBlockingQueue.take导致的,想到服务中自定义的线程池用的就是LinkedBlockingQueue。
看了一下线程池的文章发现线程使用完毕是需要将等待中的核心线程关闭的,而关闭有几种方法:
一般使用shutdown()方法和allowCoreThreadTimeOut(true)
如果为 false(默认值),则核心线程即使在空闲时也保持活动状态。
如果为 true,核心线程使用 keepAliveTime 定时等待工作。
看到这就发现为什么项目中有大量WAITING状态的线程,原来既没有手动关闭线程,也没有设置allowCoreThreadTimeOut为true,导致核心线程使用完毕后依旧在等待中
那么只需要使用executorService.allowCoreThreadTimeOut(true)就可以解决问题