多线程内存溢出问题解决之java.lang.OutOfMemoryError: unable to create new native thread

1,背景

最近在写一个爬虫程序,其中用到了多线程编程。令我郁闷的是哥写的代码居然有bug,平均运行2天左右就会遇到一次OOM。刚开始,事情比较多,没有精力去定位解决问题,只好每次OOM后花几分钟时间重启下服务。持续了几次之后,我就失去了耐性,这种手工重启的方式,不能忍了,明显不是我的风格(话说把程序写成这样,进而这样解决问题,太弱了)。所以在一个夜深人静的晚上,终于花了30分钟解决了这个问题。

2,解决问题的思路

2.1,立足从根本上解决问题

我所在的团队有个原则,必须从根本上解决问题。所以我初步思路就是,不用纠结怎么续命的方案,比如扩大jvm内存、修改系统连接数等等。诚然,这些方法有一定的作用,但是我认为这不是解决问题的根本之道。通过这些方法,最多是让OOM的时间延长而已,没有从根本上解决,最终还是程序崩溃的。
通过以下命令发现,确实是程序运行中创建了大量线程且没有释放(我这有3千多,虽说不多,但也不少了……)

ps -eLf | wc -l
3413

2.2,理清思路

由于程序中,我已经用了线程池技术,理论上是不会再出现由于启动的线程过多而导致的连接数不够用、内存溢出问题的。所以初步定位要么是JDK的bug、要么是自己的线程池用法有问题。

2.3,排除JDK 线程池管理的BUG问题

排除方式也很简单,用的ThreadPoolExecutor 和 OutOfMemoryError: unable to create new native thread 组合关键词,或者newFixedThreadPool 和 OutOfMemoryError: unable to create new native thread组合关键词,在google和百度上搜索。发现基本没有相关内容,所以基本排除了是JDK自身的问题。搜索发现的OOM问题排查、解决的文章很多,深度深浅不一,明显都不适合我的问题。
附程序中遇到的异常信息如下:

java.lang.OutOfMemoryError: unable to create new native thread
	at java.lang.Thread.start0(Native Method) ~[?:1.8.0_121]
	at java.lang.Thread.start(Thread.java:714) ~[?:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:950) ~[?:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1357) ~[?:1.8.0_121]
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) ~[?:1.8.0_121]

2.4,代码Review 发现写法错误

基本排除了外部原因,只能从自身找问题了。直觉告诉我,线程池没有生效,应该是生命周期的问题。所以查看了线程池的初始化代码,果然是有问题的:

ExecutorService pool4UpdateWebSiteInfo = Executors.newFixedThreadPool(2);

请注意,这里是非静态方法,也就是说每个class实例,都会初试化一次线程池。由于我的爬虫任务,每个子任务都是要创建一个class实例,导致线程池压根就没有发挥作用。所以直接将这个变量改为静态变量,部署测试,轻松解决。

static ExecutorService pool4UpdateWebSiteInfo = Executors.newFixedThreadPool(2);

2.5,效果

程序运行一段时间后,进程数很稳定,一直维护在一个较低的水平,如下:

ps -eLf | wc -l
593

3,相关知识点

3.1,查看系统设置的当前用户最大连接数

#查看进程资源限制
ulimit –u
#查看更多详情的话,可以用这个命令
ulimit -a

3.2,查看系统现在的线程数命令

ps -eLf | wc -l 

通过ulimit -u命令和ps -eLf | wc -l 命令查出来的数据,就可以看到自己的程序离崩溃还有多久。

以上就是本次问题排查的全部过程。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值