linux tomcat java.lang.OutOfMemoryError: unable to create new native thread

来源:互联网 发布:linux ftp更改下载目录 编辑:程序博客网 时间:2024/06/10 05:38

通过该异常的名字就可以知道:

该问题是内存溢出,不能创建新的线程。

该问题的引发是由于我们系统的用户量变大了而引起的。

附带一篇测试最大线程数的脚本

import java.util.concurrent.CountDownLatch;            public class TestNativeOutOfMemoryError {                public static void main(String[] args) {                    for (int i = 0;; i++) {                  System.out.println("i = " + i);                  new Thread(new HoldThread()).start();              }          }            }            class HoldThread extends Thread {          CountDownLatch cdl = new CountDownLatch(1);                public HoldThread() {              this.setDaemon(true);          }                public void run() {              try {                  cdl.await();              } catch (InterruptedException e) {              }          }      }


解决该问题的方案有几种:

一、根据linux下的用户创建的最大线程数进行调整(该做法需抛出root用户[因为root用户已经拥有最大的线程数])

具体做法:【使用ulimit -u 命令查看用户用于的线程数】

[root@weixinkaifaapp-36 ~]# ulimit -u
31486
[root@weixinkaifaapp-36 ~]# su - test
Last login: Tue Aug 15 10:03:33 CST 2017 on pts/1
[test@weixinkaifaapp-36 ~]$ ulimit -u
4096
[test@weixinkaifaapp-36 ~]$ 

以上可以看出我的root用户拥有可31486个线程的权限[我们生产实际的配置有2万5千个]

但是test用户只能创建4096个线程,一般应用的启动都是由较低权限的用户启动的,故在系统中的创建的线程数超过了4096些时,就会导致系统的内存溢出。

解决方案:

修改配置文件
$ cd /etc/security/limits.d/
$ ll

【查看配置列表  不同的系统版本所查到的配置名称不一定相同】
$ vim 20-nproc.conf

# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.


*          soft    nproc     4096
root       soft    nproc     unlimited


可以看到在root用户下拥有最大的线程数,而其他用户只有4096个线程数创建的权利。

具体应该配置多大的线程数需要根据不同的需求而定了。


二、使用Apache Tomcat 集群

这种做法可以使用nginx进行分发,然后使用redis进行控制session回话,使用nfs进行资源共享,做法比较简单,但是缺点是公司投入较大,由于我们公司并不额外提供服务器,故这个做法,我这里没有进行实现。(但是我们的系统是nginx+2个tomcat+2个服务器+1个nfs服务器组成的)


三、需要tomcat启动的jvm参数(这里不建议这样配置,因为风险高,需要测试很久)

具体计算公式如下: 
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads 


MaxProcessMemory 指的是一个进程的最大内存
JVMMemory         JVM内存
ReservedOsMemory  保留的操作系统内存
ThreadStackSize      线程栈的大小


在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。 


结合上面例子我们来对公式说明一下: 
MaxProcessMemory 在64位的 windows下是 4G
JVMMemory   eclipse默认启动的程序内存是64M
ReservedOsMemory  一般是130M左右
ThreadStackSize 32位 JDK 1.6默认的stacksize 325K左右
公式如下:
(4*1024*1024-64*1024-130*1024)/325 = 12294 


由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。 


因为ThreadStackSize 越大 除的越多,创建的线程也就越少。


对于linux系统内存的查看可以使用free命令[默认单位是k]

但是我一般使用free -m命令通过以M的方式显示系统内存

[root@weixinkaifaapp-36 ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          3953       3818        135         51          0         43
-/+ buffers/cache:       3774        179
Swap:         3983       3983          0
[root@weixinkaifaapp-36 ~]# 

total为该系统总共的内存大小,used为已使用的内存大小,free为空闲的内存大大小。

对于tomcat进行配置jvm:

linux下修改Catalina.sh文件[在{CATALINA_HOME}/bin目录下]

添加:JAVA_OPTS='-Xms512m -Xmx1024m' 
要加“m”说明是MB,否则就是KB了,在启动tomcat时会报内存不足。 
-Xms:初始值 
-Xmx:最大值 
-Xmn:最小值

例如我们配置的:

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "

然后重启tomcat,配置即可生效。


最后列几个重要的参数:

(1)-Xms,jvm启动时,初始分配的堆/栈内存

(2)-Xmx,JVM最大允许分配的堆/栈内存,按需分配
(3)-Xss,设定每个线程的堆栈大小

(4)-XX:PermSize,JVM初始分配的非堆内存

(5)-XX:MaxPermSize,JVM最大允许分配的非堆内存,按需分配


阅读全文
0 0
原创粉丝点击