先说下问题是怎么来的吧。
项目背景:现在正在做的是一个爬虫项目,爬虫主要爬取各大电商的商品数据,然后清洗进入索引库,为客户提供搜索导购服务(说白了就是导购服务)。爬取这些数据的要求:实时性、准确性。重点是实时性,需要爬虫保证每天至少爬取一遍这些数据,对商品库进行更新。那么问题就来了,爬虫肯定是多线程的,而且要求执行效率要特别高,就是要快。从第一个版本的纯手工方式,到第二个版本的多线程调度和任务分配(主要是方便监控)。
问题表现:项目在本机跑起来100个线程毫无压力,而且cpu利用率也特别好。所以就直接部署到了测试环境的服务器上,跑了一个晚上第二天早上依赖发现内存溢出了,而且这个溢出以前没怎么见过,一般大家场景的内存溢出都是Java heap space或PermGen space ,而我这次遇到的是GC overhead limit exceeded,相信大家也很少遇到。(如果大家遇到前面两种请参考java内存溢出的三种情况和解决方案)
解决思路:
1、首先肯定是百度咯,百度不行翻出去google咯,找一些资料看了下,官方也有说明。问题根本原因是jvm gc行为中超过98%以上的时间去释放小于2%的堆空间时会报这个错误。
2、为什么本机可以,到了测试服务器上不行了,然后一看服务器内存居然4G,运维的兄弟太坑了,给分那么点,我笔记本都是8g呢。后来先要求加内存到8G,但是还是没解决根本问题。
3、查看了下内存使用情况,还是溢出了,导致新的线程无法创建,测试服务器使用线程池开了300个线程,不至于啊。所以只有修改tomcat的默认配置了,其实就加了2个参数,(linux就修改catalina.sh,windows当然是修改catalina.bat,加在文件的开头)
HEAP_SIZE="6000M"
NEW_SIZE="4200M"
另外还多加了两个参数 ,提供jconsole连接的,方便监控jvm,如果再出问题就得靠这玩意儿了。
SERVER_IP="192.168.16.12"
SERVER_PORT="1909"
下图是连接jconsole后监控的界面,大家会发现GC频率并不高,但是很高效