`

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

    博客分类:
  • j2ee
 
阅读更多

一、认识问题:

首先我们通过下面这个  测试程序  来认识这个问题:
运行的环境  (有必要说明一下,不同环境会有不同的结果):32位 Windows XP,Sun JDK 1.6.0_18, eclipse 3.4,
测试程序:

01 import java.util.concurrent.CountDownLatch;
02  
03 public class TestNativeOutOfMemoryError {
04  
05      public static void main(String[] args) {
06  
07          for ( int i = 0 ;; i++) {
08              System.out.println( "i = " + i);
09              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 }

不指定任何JVM参数,eclipse中直接运行输出,看到了这位朋友了吧:
i = 5602

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)

二、分析问题:

这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下:  
(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads  
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory         JVM内存
ReservedOsMemory  保留的操作系统内存
ThreadStackSize      线程栈的大小

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

结合上面例子我们来对公式说明一下:  
MaxProcessMemory 在32位的 windows下是 2G
JVMMemory   eclipse默认启动的程序内存是64M
ReservedOsMemory  一般是130M左右
ThreadStackSize 32位 JDK 1.6默认的stacksize 325K左右
公式如下:
(2*1024*1024-64*1024-130*1024)/325 = 5841 
公式计算所得5841,和实践5602基本一致(有偏差是因为ReservedOsMemory不能很精确)

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

咦,有点背我们的常理,恩,让我们来验证一下,依旧使用上面的测试程序,加上下面的JVM参数,测试结果如下:  
ThreadStackSize      JVMMemory                    能创建的线程数
默认的325K             -Xms1024m -Xmx1024m    i = 2655
默认的325K               -Xms1224m -Xmx1224m    i = 2072
默认的325K             -Xms1324m -Xmx1324m    i = 1753
默认的325K             -Xms1424m -Xmx1424m    i = 1435
-Xss1024k             -Xms1424m -Xmx1424m    i = 452
 
完全和公式一致。

三、解决问题:  
1, 如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
2, 如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:
a, MaxProcessMemory 使用64位操作系统
b, JVMMemory   减少JVMMemory的分配
c, ThreadStackSize  减小单个线程的栈大小

//—————————————————————————–华丽的分割线——————————————————————————————//

星期一早上到了公司,据称产品环境抛出了最可爱的异常 —OutOfMemory, 它是这样来描述他自己的:

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

而且这位仁兄竟然还堂而皇之地同时出现在了 3 application 里面,所有应用全部遭殃。

那可爱的 OOM 是如何产生的呢?直接原因是创建的线程太多了,根本原因是某个地方的内存限制了。

搜罗了一下在网上找到了一个计算公式:

(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads  

MaxProcessMemory :进程最大的寻址空间,但我想这个值应该也不会超过虚拟内存和物理内存的总和吧。关于不同系统的进程可寻址的最大空间,可参考下面表格:

Maximum Address Space Per Process

Operating System

Maximum Address Space Per Process

Redhat Linux 32 bit

2 GB

Redhat Linux 64 bit

3 GB

Windows 98/2000/NT/Me/XP

2 GB

Solaris x86 (32 bit)

4 GB

Solaris 32 bit

4 GB

Solaris 64 bit

Terabytes

JVMMemory: Heap + PermGen

ReservedOSMemory Native heap JNI

便可推导出单个 JVM Instance可支持的最大线程数的估计值:

(MaxProcessMemory<固定值 > – Xms<初始化值,最小值 > – XX:PermSize<初始化值,最小值 > – 100m<估算值 >) / Xss = Number of threads<最大值 >

在本地 (32bit windows)试了试,可达的线程的最大值差不多就是这个数,它不受物理内存的限制,会利用虚拟内存,从任务管理器看到 memory已经是 5500 m左右了(开了两个 jvm),我机器的物理内存是 2g,也不知道这个准不准,后来还抛出了“ unable to create new native thread ”的兄弟“ Exception in thread "CompilerThread0" java.lang.OutOfMemoryError: requested 471336 bytes for Chunk::new. Out of swap space?“。

本地测完了后,就该轮到 dev环境了, linux2.6 64bit,双核, 8G(虚拟机),总的物理内存是 16g。在上面整了一下,创建到了 15000多个线程的时候挂掉了。此时其他 application也不能创建新的线程,而且 db也报错了,操作系统不能 fork新的线程了。这应该是操作系统的哪里限制了新线程的创建,

·          max thread linux2.6似乎是 32000

·          最大可用内存:物理内存 +虚拟内存

·          配置,在 linux可以限制可用资源的大小, show一下这些参数

core file size          (blocks, -c) 0

data seg size           (kbytes, -d) unlimited

file size               (blocks, -f) unlimited

pending signals                 (-i) 1024

max locked memory       (kbytes, -l) 32

max memory size         (kbytes, -m) unlimited

open files                      (-n) 65536

pipe size            (512 bytes, -p) 8

POSIX message queues     (bytes, -q) 819200

stack size              (kbytes, -s) 10240

cpu time               (seconds, -t) unlimited

max user processes              (-u) 16384

virtual memory          (kbytes, -v) unlimited

file locks                      (-x) unlimited

为了进一步确定在 linux上一个 jvm因为达到了最大寻址空间 OOM了,不会影响其他 jvm,我在 Linux做了进一步测试,一开始用 Sun文档中说的最大寻址空间 3G试了一下,发现根本不对,达到了 3G后还是非常 high地在创建新的线程。于是出动超级无敌变态的 JVM初始化配置。

oracle   27408 27017 12 13:45 ?        00:00:07 /home/oracle/ias1013/FWAPP/FWDev/jdk/bin/java -server -Xmx4096m -Xms4096m -XX:+HeapDumpOnOutOfMemoryError -XX:PermSize=4096m -XX:MaxPermSize=4096m -XX:HeapDumpPath=/home/oracle/ias1013/FWAPP/FWDev/j2ee/OC4J_OOMTest/workEnv/log -Xss100m

结果在 create 3379个线程后,“ unable to create new native thread ”出现了,这时其他 jvm都是可以 create新线程的。如果按照上面公式计算, linux 64bit 2.6kernel,它的最大寻址空间肯定超过了 300g,当然应该还没有达到可用内存的限制,因为其他 JVM还 create新线程。

我还怀疑是不是 oracle application server上的某个配置参数限制了总的线程数,影响了所有 application,但我们的产品环境一个 application就是一个单独的application server。

现在基本上可以确定是操作系统哪里设置错了,我想 System team的帅哥们应该把产品环境的某个参数配置错了,系统本身的影响肯定不会有了,因为产品环境上我们只 create 800左右个线程,就OOM了,那应该就是配置的问题了,怀疑的参数有下面四个

max user processes              (-u) 2048

virtual memory          (kbytes, -v) unlimited

max memory size         (kbytes, -m) unlimited

stack size              (kbytes, -s) 10240

最后发现只有 max user processes  virtual memory对总的线程数有影响,我把 max user processes降到 2048后,发现此时只能创建  2000左右个线程了 (Xms64m, Xss1m),进一步地把 virtual memory下调到 2048000K发现能创建的就更少了 1679 Xms64m, Xss1m),而它只会对当前shell起作用,而多个application server应该是不同的shell,所以他是打酱油的 。另外两个参数好像就是来做做俯卧撑的,操作系统 stack size是不应该会有什么影响,我们把它上调到 102400,还是可以创建 2000左右的线程数( max user processes), 因为 java有自己的线程模型,它的栈的大小是用 Xss来控制的。 Max memory size不知道是啥东东,照理说如果是最大内存应该不会只在旁边做俯卧撑,那这个参数到底是春哥还是曾哥,查了一下 man ulimit,有下面解释

              -a     All current limits are reported

              -c     The maximum size of core files created

              -d     The maximum size of a process data segment

              -f     The maximum size of files created by the shell

              -l     The maximum size that may be locked into memory

              -m     The maximum resident set size (has no effect on Linux)

              -n     The maximum number of open file descriptors (most systems do not allow this value to be set)

              -p     The pipe size in 512-byte blocks (this may not be set)

              -s     The maximum stack size

              -t     The maximum amount of cpu time in seconds

              -u     The maximum number of processes available to a single user

              -v     The maximum amount of virtual memory available to the shell

Has no effect on Linux”就足以证明它确实只是来做做俯卧撑的。最后查出只有“ max user processes”会对所有 application能创建总的线程数有限制。

分享到:
评论

相关推荐

    内存不足OOM java.lang.OutOfMemoryError.

    3. **无法创建新的本地线程 (Unable to create new native thread)**: - 每个Java应用在操作系统上都表现为一个或多个线程。当JVM尝试创建新线程但操作系统报告无可用资源时,会抛出此错误。 - 这可能是由于系统...

    问题分析:java.lang.OutOfMemoryError unable to create new native thre

    【Java虚拟机内存溢出分析】:当遇到`java.lang.OutOfMemoryError: unable to create new native thread`错误时,这通常表示系统无法为新的Java线程分配足够的内存,即操作系统层面的资源耗尽,而非Java堆内存不足。...

    OutOfMemoryError_8种典型案例分享

    5. 无法创建新的原生线程(Unable to create new native thread) 当JVM尝试创建新的线程时,如果无法获取足够的原生内存来分配新线程的栈空间,就会抛出该错误。通常发生在系统限制了线程数量或是原生内存不足时。 ...

    java内存溢出原因

    - **错误日志**:`java.lang.OutOfMemoryError: unable to create new native thread` 和 `java.lang.OutOfMemoryError: request bytes for ... Out of swap space?` - **原因**:可能由于Java堆设置过大导致...

    关于java堆内存溢出的几种情况

    【情况五】:`java.lang.OutOfMemoryError: unable to create new native thread` 这表明系统无法创建新的原生线程,可能是由于线程栈空间不足或者系统资源限制。解决方法包括减少单个线程栈大小(使用`-Xss`参数)...

    OutOfMemoryError Handbook

    OutOfMemoryError的8种经典案例,Java heap space、GC overhead limit exceeded、Permgen space、Metaspace、Unable to create new native thread、Out of swap space?、Requested array size exceeds VM limit、...

    Dubbo无法创建新线程异常解决方案.docx

    在使用Dubbo进行分布式服务调用的过程中,可能会遇到“无法创建新线程”的异常情况,具体表现为`java.lang.OutOfMemoryError: unable to create new native thread`。此类异常通常出现在系统资源紧张的情况下,特别...

    教你分析9种OOM常见原因及解决方案.docx

    5. Unable to Create New Native Thread 错误 * 原因分析:JVM 向 OS 请求创建 native 线程失败 * 解决方案:增加 JVM 的堆内存空间、调整 JVM 的线程池大小、优化线程的使用 6. Requested Array Size Exceeds VM ...

    TOMCAT内存溢出之解决方法

    系统会提示出错,前台错误为:HTTP Status 500-Dispatch[EAITool] to method listCurTree retrun an exception,后台错误为:java.lang.OutOfMemoryError: unable to create new native thread。 解决方法: 为了...

    JVM+多线程.pdf

    - **java.lang.OutOfMemoryError: unable to create new native thread**:无法为线程分配内存。 - **java.lang.OutOfMemoryError: request bytes for**:地址空间不足。 解决内存溢出问题,首先需要查看监控工具...

    linux 测试环境线程问题解决

    java.lang.OutOfMemoryError: unable to create new native thread ``` 或是在启动服务时收到: ``` /etc/profile: fork: retry: Resource temporarily unavailable ``` 这些错误通常表明系统中的线程资源已经...

    将应用部署到weblogic10及oracle linux时遇到的问题 .pdf

    首先,我们遇到的第一个问题是“意外的异常”和“java.lang.OutOfMemoryError: unable to create new native thread”。这通常发生在尝试上传大型应用war包至WebLogic管理服务器时。由于应用较大,系统内存不足,...

    tomcat内存溢出总结

    3. **OutOfMemoryError: unable to create new native thread** - 当系统无法为新的线程分配内存时,会出现此类错误。这通常是由于操作系统级别的限制导致的。 #### 二、内存溢出的原因分析与解决策略 ##### 1. ...

    Dubbo线程模型(结合Linux线程数限制配置的实战经验分享).docx

    当应用程序尝试创建超过这个限制的线程时,可能会抛出`java.lang.OutOfMemoryError: unable to create new native thread`异常。这个限制是防止恶意或意外的进程消耗过多系统资源,导致所谓的“fork炸弹”。 实战...

    性能分析 -线程

    - **无法创建新原生线程**(`java.lang.OutOfMemoryError: unable to create new native thread`):当操作系统没有足够的资源来创建新线程时发生,可以通过调整`-Xss`参数来减少分配给单个线程的栈空间大小。...

    java 中Executor, ExecutorService 和 Executors 间的不同

    Java 中 Executor, ExecutorService 和 Executors ...通过理解它们之间的区别,我们可以更好地使用线程池来提高应用的响应时间,避免“java.lang.OutOfMemoryError: unable to create new native thread”之类的错误。

Global site tag (gtag.js) - Google Analytics