一、问题:
春节将至,系统访问量进入高峰期。随之系统出现了异常:java.lang.OutOfMemoryError: unable to create new native thread。在解决这个问题中,尝试了各种方法,最后竟然是因为它......
二、解决办法:
1、 关于这个问题,一开始猜想是因消息队列(activemq)引起的,因为处理数据较多,开启的线程数较多导致,因此对MQ搭建了集群。
MQ集群搭建方法:http://blog.csdn.net/jiangxuchen/article/details/8004561
但是搭建集群后发现,并不是,问题依旧。
继续......
2、 接下来怀疑是系统里开的线程数太多,在优化后,问题仍然存在。
继续......
3、 内存调优,减小xss值、JVM内存,仍然解决不了。
继续......
4、 几番周测,在整理思路后,决定首要任务就是如何重现该问题,于是编写测试程序,测试出操作系统最大能够创建的线程数:
1 import java.util.concurrent.CountDownLatch;
2
3 public class TestNativeOutOfMemoryError {
4
5 public static void main(String[] args) {
6
7 for (int i = 0;; i++) {
8 System.out.println("i = " + i);
9 new Thread(new HoldThread()).start();
10 }
11 }
12
13 }
14
15 class HoldThread extends Thread {
16 CountDownLatch cdl = new CountDownLatch(1);
17
18 public HoldThread() {
19 this.setDaemon(true);
20 }
21
22 public void run() {
23 try {
24 cdl.await();
25 } catch (InterruptedException e) {
26 }
27 }
28 }
运行后:
i = 982 Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:597) at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:20)
问题重现,在反复运行几次后发现,生产系统最大只能创建980多个线程,生产系统操作系统64位centeros,jdk1.7,64G内存。而我本地PC电脑都可以创建2500左右。
感觉原因快找到了,切换到运行账户使用命令:
$ su Bst118
$ ulimit -u
$ 1024
生产上所有程序都是在Bst118账户下运行,于是查看该账户下所有的线程数总和为950,也即是说,随时都可能会超过1024,导致内存溢出。查看看进程当前运行的线程数命令为:pstree -p 3660 | wc -l
原因找到,操作系统对运行程序的账户有最大线程数限制。
$ vim /etc/security/limits.d/90-nproc.conf
打开后发现除了root,其他账户都限制在1024个。
于是增加一条:Bst118 soft nproc 20000
为什么设置为20000,因为测试后发现,在运行到35000左右,系统就报内存溢出了,操作系统所有命令都不能使用,因此将程序最大线程数限制在20000。
修改后再没出现内存溢出错误。问题解决。
三、思考
1、经过总结,在遇到问题后,不能盲目的到处修改,首先要做的就是重现问题,顺藤摸瓜,逐步的找出根本原因。