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

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

运行中的项目报错,之前运行还好着门突然报错,看到oom下意识认为堆空间不够了添加了-Xms1024M -Xmx2048M提高了堆内存还是报错,上google搜索后发现有人也碰见这种错误,最后我的问题是通过修改-Xss256k解决了,看到一篇博客讲的不错,然后翻译过来,做个参考:

原文链接

翻译如下

怎么解决 java.lang.OutOfMemoryError: unable to create new native thread

在java程序中你可能会偶然发现两种类型的Out of Memory错误:

  • java.lang.OutOfMemoryError Java heap space error : 这个异常通常发生在应用程序想要在堆空间申请更多的内存但是堆空间没有足够的内存提供的情况。即便是你的物理内存足够的情况下,此种情况可以通过Xmx参数来修改你的jvm堆内存大小来解决。

  • java.lang.OutOfMemoryError: Unable to create new native thread :当jvm想要像操作系统申请创建一个线程的时候,但是操作系统不能够创建一个本地的线程来映射,这个时候会抛出该异常。

解决方式

1)系统参数的设置

/proc/sys/kernel/threads-max这个文件提供了系统级别的线程参数设置。root用户可以通过下面的方式改变这个值为你自己想要的值;

$ echo 100000 > /proc/sys/kernel/threads-max

你可以通过查看该文件来检查当前系统的默认配置值:

$ cat /proc/loadavg
0.41 0.45 0.57 3/749 28174

注意第4个参数:3/749第一个是当前正在执行的内核调度实体(进程、线程)的数量;这将小于或等于cpu的数量。斜杠后面的值是当前系统上存在的内核调度实体的数量。在本例中,您正在运行749个线程

2)检查每个用户的进程数

在Linux机器上,线程本质上只是具有共享地址空间的进程。因此,您必须检查您的操作系统是否为用户提供了足够的进程。这可以通过下面方式查询:

ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 515005
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 4096
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

默认的每个用户的最大进程数是1024。查询当前正在运行的进程数通过下面方式进行:

$ ps -elf | wc -l  
220

该方式没有考虑该进程产生的线程的数量,查看线程的数量通过下面方式查询:

$ ps -elfT | wc -l  
385

正如你看到的结果所展示,由于使用ps -elfT线程的关系,查询的结果数量显著的增加了。正常情况下不会导致什么问题,但是你的java程序可能会超过系统的限制。我们继续,查看一下jboss产生了多少个线程(原作者这里是在使用了jboss的时候产生的该错误),你可以使用下面方式查看:

$ ps -p JBOSSPID -lfT | wc -l

上面的shell命令返回的结果是指定的PID进程所创建的轻量级线程的数量,这个数量应该和jstack查询出来的数量一致:

$ jstack -l JBOSSPID | grep tid | wc -l

现在您应该有证据表明您需要为用户增加进程的数量。这可以做到与以下命令:

$ ulimit -u 4096

3)检查你的PID线程限制

一旦您计算了线程的数量,那么您应该验证您没有达到内核指定的系统限制。你可以通过下面命令执行:

$ sysctl -a | grep kernel.pid_max  
 
kernel.pid_max = 32768

4)减少线程栈空间大小

因为-Xss的值是表示每个线程占用的内存的大小,减少该参数的值可以增大可创建的线程的数量,能显著的提高并发量

如果无法修改操作系统设置,可以使用的另一个选项是减小堆栈大小.JVM的内存实现很有趣,可用的堆内存越多(不一定是非得是正在使用的堆内存)可用的栈内存就越小。线程的创建依赖栈空间内存的大小。适当的减少每个线程占用的栈内存,可以提高系统的并发;

我们检查系统默认的每个线程的栈空间大小:

$ java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
     intx CompilerThreadStackSize                   = 0                                   {pd product}
     intx ThreadStackSize                           = 1024                                {pd product}
     intx VMThreadStackSize                         = 1024                                {pd product}
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

从jdk1.5开始默认-Xss(也就是ThreadStackSize)的大小默认是1024KB,也就是1M。在JBoss EAP 6 / WildFly版本,默认的线程栈空间大小是228kb,你可以通过修改-Xss的大小来调整该值你可以通过下面的设置来修改:

JAVA_OPTS="-Xms128m -Xmx1303m -Xss256k"

在域模式中,您可以在不同的级别(主机、服务器组、服务器)配置jvm参数。你可以设置请求的堆栈大小如下所示:

<jvm name="default">
    <heap size="64m" max-size="256m"/>
    <jvm-options>
        <option value="-server"/>
        <option value="-Xss256k"/>
    </jvm-options>
</jvm>

参考文献:

原文链接:http://www.mastertheboss.com/jboss-server/jboss-monitoring/how-to-solve-javalangoutofmemoryerror-unable-to-create-new-native-thread

知乎大牛讲解:https://www.zhihu.com/question/64685291

另外一篇博客和翻译的原文:

原文:https://plumbr.io/outofmemoryerror/unable-to-create-new-native-thread

翻译:https://blog.csdn.net/renfufei/article/details/78088553

简书的一篇博客:https://www.jianshu.com/p/b0df25bae79d

posted @ 2019-12-17 21:14  bartggg  阅读(303)  评论(0)    收藏  举报