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

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

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

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

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

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值