高并发请求服务器时,经常出现如下异常:java.lang.OutOfMemoryError: unable to create new native thread的解决方法

来源:互联网 发布:手机流量软件 编辑:程序博客网 时间:2024/05/22 12:24

高并发请求服务器时,经常出现如下异常:java.lang.OutOfMemoryError: unable to create new native thread,对于此种情况,出现这种情况,是什么原因呢,又该如何解决呢

1、原因

问题的表象解释是,你的服务器的单个进程已经不能再创建更多的线程了,
那为什么会出现这种情况呢?
原因有几种情况:
1.你的应用创建了太多线程了,理论上讲,一个应用进程,创建多个线程,确实可以提高应用程序的并发能力,但线程的数量并不是越大,你的应用程序并发能力就越强的。
2.你的服务器并不允许你的应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,你的应用创建超过这个数量,就会报java.lang.OutOfMemoryError: unable to create new native thread

2、解决方法

1.想办法降低你应用程序创建线程的数量,既然我们已经知道,线程的数量和应用程序并发能力不是正比,就得在应用层面,分析应用是否真的需要创建这么多线程,如果不是,果断改代码,将线程数降到最低
2.对于有的应用,确实需要创建很多线程,远超过linux系统的默认1024个线程的限制,可以通过修改linux服务器配置,扩大linux默认限制
3.修改应用程序单线程占用的堆栈大小,线程越多,占用的堆栈空间就越多,如果内存空间不够大,自然也无法创建更多的线程。如果你的老板或客户足够阔气,要多少内存给多少,可以忽略这个

2.1、降低应用程序创建线程的数量

应用程序是你负责的,这个只能你自己想办法解决
原则有几个:
1.在必须用线程的情况下,如果可以用线程池的,尽量用线程池
2.检查线程池默认开启线程的个数,如果只想开启一个线程,代码却设置了多个,如果有这种情况,坚决改之
3.检查线程池的类型,newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,这几种线程池差别还是很大的,不能乱用
4.检查线程泄漏,所谓线程泄漏,就是你只管生,不管死,只管创建,不管线程的销毁,结果线程的句柄你也没有管理起来,导致进程中创建了无数个僵尸线程,出现unable to create new native thread只是时间问题

2.2、修改Linux服务器配置

vi /etc/sysctl.conf末尾追加下面的三行vm.max_map_count = 1000000kernel.pid_max = 1000000kernel.threads-max = 1000000保存后,执行sysctl -p使其生效
vi /etc/security/limits.d/90-nproc.conf找到这一行,*     soft    nproc     1024修改最后的数字为102400

退出登录工具(SecureCRT),重新连接 执行ulimit -u 命令查看是否为修改后的值
注意:此处的数字值不是随意改大都能生效,如果超出系统能设置的最大值时,系统自动以系统最大值为有效。
附:系统最大值计算方法:
default_nproc = total_memory/128K
total_memory获取:cat /proc/meminfo |grep MemTotal,单位KB
举例:

$ cat /proc/meminfo |grep MemTotalMemTotal:       16425852 KB$ echo "16425852 / 128"| bc 128326

即该服务器所能设置的nproc最大值为128326

2.3、修改应用程序单线程占用的堆栈大小

配置你自己应用单个线程占用的内存资源,以java-web应用部署在tomcat中为例:

vi catalina.sh

找到JAVA_OPTS配置项

JAVA_OPTS="-Xms512m -Xmx1536m -XX:MaxNewSize=128m -XX:PermSize=128m -XX:MaxPermSize=256m"

在-Xmx1536m后添加“-Xss325k”参数,如下

JAVA_OPTS="-Xms512m -Xmx1536m -Xss325k -XX:MaxNewSize=128m -XX:PermSize=128m -XX:MaxPermSize=256m"

保存并重启tomcat

-Xss参数,是用于设置单线程占用的内存资源,该值并不是随意设置,jdkJDK5.0以后每个线程堆 栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误.

JVM可创建的最大线程数限制因素:
线程堆栈大小——》进程的最大内存——》操作系统位数

阅读全文
0 0