“ java.lang.OutOfMemoryError:无法创建新的本机线程”


124

"java.lang.OutOfMemoryError : unable to create new native Thread32k线程后,我们在8GB RAM VM上获得了“”(ps -eLF | grep -c java)

但是,"top" and "free -m" shows 50% free memory available。JDk是64位的,并已在HotSpot和JRockit上试用过。服务器具有Linux 2.6.18

我们还尝试了OS stack size (ulimit -s)调整和最大进程(ulimit -u)限制,limit.conf增加了,但是都是徒劳的。

我们还尝试了几乎所有可能的堆大小组合,将其保持为低,高等。

我们用来运行应用程序的脚本是

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

谢谢回复。

我们已经尝试编辑/etc/security/limits.conf和ulimit,但是仍然一样

[root@jboss02 ~]# 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) 72192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
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) 72192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

11
操作系统对您可以创建的线程数有限制。为什么创建的线程数超过32k?您的系统很可能没有数千个处理器核心,因此创建这么多线程是没有用的。请改用线程池(ExecutorService)。
耶斯珀(Jesper)

谢谢回复。我们正在使用一个开源库,并试图对其进行负载测试。任何一个开源库都在创建这么多线程。但是我不明白的是,当“顶部”显示50%的可用内存时,为什么会出现OutOfMemory错误。
迪帕克·特瓦尼

我们在ICE4j库中使用的开源库
Deepak Tewani

11
OutOfMemoryError错误确实必然意味着堆空间,或“一般”的RAM,精疲力竭。在这种情况下,很明显失败是由于OS没有足够的资源来分配额外的线程。拥有50%的可用内存与此特定故障无关。
Andrzej Doyle

1
创建新线程还需要哪些其他资源。我们的印象是,如果增加RAM,那么我们可能能够创建更多线程。请指导一下
迪派Tewani

Answers:


80

即使异常名称强烈建议也不是内存问题,而是操作系统资源问题。您用完了本机线程,即操作系统将允许您的JVM使用多少线程。

这是一个不常见的问题,因为您很少需要那么多。您是否有很多无条件线程产生,这些线程应该在哪里但不能结束?

您可能会考虑尽可能在执行器的控制下重写为使用Callable / Runnables。有很多具有各种行为的标准执行程序,您的代码可以轻松控制这些执行程序。

(限制线程数量的原因有很多,但是它们因操作系统而异)


谢谢回复。我们正在使用开源库ICE4j并尝试对其进行负载测试。当我们知道服务器上还有50%的内存时,就不能增加操作系统中的线程限制。
迪帕克·特瓦尼

可能,但是我认为这样对您没有帮助。如果在进行负载测试时资源不足,则需要能够控制应用程序中发生的事情。为什么同时有32000个线程处于活动状态?
托尔比约恩Ravn的安徒生

我们正在创建11K客户端,该客户端使用32K线程在UDP套接字上读取,写入数据。在这32 K线程中,有10K线程是保持活动状态的线程,用于保持套接字打开
Deepak Tewani

我相信这个问题可以在现代Web服务器中解决。udp还会丢失数据包-您不只是使用Web服务器的任何原因吗?
托尔比约恩Ravn的安徒生

7
因为OutOfMemory异常应该被命名为OutOfResources。操作系统无法提供所需的资源。(而事实证明,我不知道ice4j)
托尔比约恩Ravn的安徒生

14

在负载测试期间遇到了相同的问题,原因是由于JVM无法进一步创建新的Java线程。下面是JVM源代码

if (native_thread->osthread() == NULL) {    
// No one should hold a reference to the 'native_thread'.    
    delete native_thread;   
if (JvmtiExport::should_post_resource_exhausted()) {      
    JvmtiExport::post_resource_exhausted(        
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | 
        JVMTI_RESOURCE_EXHAUSTED_THREADS, 
        "unable to create new native thread");    
    } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread");  
} Thread::start(native_thread);`

根本原因:当JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR(资源耗尽(意味着内存耗尽))或JVMTI_RESOURCE_EXHAUSTED_THREADS(线程耗尽)时,JVM引发此异常。

在我的情况下,Jboss创建了太多线程来满足请求,但是所有线程都被阻塞了。因此,JVM耗尽了线程以及内存(每个线程都保存了memory,因为每个线程都被阻塞,所以不释放内存)。

分析Java线程转储后,发现有将近61K线程被我们的方法之一阻塞,这导致了此问题。以下是线程转储的一部分

"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
   java.lang.Thread.State: BLOCKED (on object monitor)

方法是如何阻止的?再也不回来了?
托尔比约恩Ravn的安德森

8

您的操作系统可能不允许您尝试创建的线程数,或者您在JVM中遇到了一些限制。特别是如果它是一个32k的整数,则很可能是一种或另一种限制。

您确定您确实需要32k线程吗?大多数现代语言都对可重用线程池提供了某种支持-我确信Java也已经具备了一些功能(例如ExecutorService,如用户Jesper所述)。也许您可以从这样的池中请求线程,而不是手动创建新线程。


1
感谢您的答复我们正在使用开源库ICE4j并尝试对其进行负载测试。当我们知道服务器上还有50%的内存时,就不能增加操作系统中的线程限制。
Deepak Tewani 2013年

1
我们正在创建11K客户端,该客户端使用32K线程在UDP套接字上读取,写入数据。在这32 K线程中,有10K线程是保持活动状态的线程,用于保持套接字打开
Deepak Tewani

7

我建议也查看线程堆栈大小,看看是否创建了更多线程。对于Linux OS上的64位VM ,JRockit 1.5 / 1.6的默认线程堆栈大小为1 MB。32K线程将需要大量的物理和虚拟内存才能满足此要求。

尝试将堆栈大小减小到512 KB,以查看它是否有助于为您的应用程序创建更多线程。我还建议探索水平扩展,例如将应用程序处理分配到更多物理机或虚拟机上。

使用64位VM时,真正的限制取决于操作系统物理和虚拟内存的可用性以及操作系统调整参数(例如ulimitc)。我还建议以下文章作为参考:

OutOfMemoryError:无法创建新的本机线程–神秘化的问题


5

如果通过systemd启动jvm,则在某些linux操作系统中,每个进程可能有一个maxTasks限制(任务实际上是线程)。

您可以通过运行“服务状态”进行检查,并检查是否存在maxTasks限制。如果存在,则可以通过编辑/etc/systemd/system.conf并添加配置来将其删除:DefaultTasksMax = infinity


3

由于在bash中使用top时没有出现幻影进程,因此我遇到了同样的问题。这阻止了JVM产生更多线程。

对我来说,它解决了列出所有带有jps的 Java进程(只需jps在您的Shell中执行)并使用kill -9 pidbash命令为每个幽灵进程单独杀死它们的问题。

在某些情况下这可能会有所帮助。


2

java.lang.OutOfMemoryError: Unable to create new native thread每当JVM从操作系统请求新线程时,您都有机会面对。只要基础操作系统无法分配新的本机线程,就会抛出此OutOfMemoryError。本机线程的确切限制取决于平台,因此建议通过运行类似于以下链接示例的测试来找出这些限制。但是,一般而言,造成这种情况java.lang.OutOfMemoryError: Unable to create new native thread的过程分为以下几个阶段:

  1. JVM内部运行的应用程序请求新的Java线程
  2. JVM本机代码代理向OS创建新本机线程的请求OS尝试创建需要将内存分配给该线程的新本机线程
  3. 操作系统将拒绝本机内存分配,原因是32位Java进程大小耗尽了其内存地址空间(例如,达到(2-4)GB进程大小限制)或操作系统的虚拟内存已被完全耗尽
  4. java.lang.OutOfMemoryError:无法创建新的本机线程错误被抛出。

参考:https : //plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread


2

要查找正在创建线程的进程,请尝试:

ps huH

我通常将输出重定向到文件并离线分析文件(每个进程的线程计数是否符合预期)


1

如果您的作业由于节点上的内存不足而失败,则可以减少最大映射数和缩减器的数量,然后JVM选择它们的数量。通常必须根据您的数据节点特定的硬件来增加mapred.child.java.opts(默认值为200Xmx)。

该链接可能会有所帮助...请检查


1
我们都已经尝试过该链接上的更改。但结果是相同的:(
Deepak Tewani

1

您的JBoss配置存在一些问题,/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms和Xmx将您的JBoss内存使用限制为配置值,因此从8Gb开始,您拥有的服务器仅使用512M +为自己的目的添加一些额外的东西,增加该数字,记住为操作系统和在那里运行的其他东西留出一些空闲空间,尽管有一些糟糕的代码,但仍可以使它运行。如果可以的话,修复代码也很好。


1

由于以下两个原因,此错误可能浮出水面:

  • 内存中没有空间容纳新线程。

  • 线程数超过了操作系统限制。

我怀疑线程数是否超出了Java进程的限制

因此,可能的原因是内存问题。要考虑的一点是

线程不在JVM堆中创建。它们是在JVM堆之外创建的。因此,如果RAM中剩余的空间较小,则在分配JVM堆之后,应用程序将运行到“ java.lang.OutOfMemoryError:无法创建新的本机线程”中。

可能的解决方案是减少堆内存或增加总体内存大小


0

我遇到了同样的问题,事实证明这是对Java API的不当使用。我正在使用批处理方法初始化一个构建器,这种方法不应该被多次初始化。

基本上我在做类似的事情:

for (batch in batches) {
    process_batch(batch)
}

def process_batch(batch) {
    var client = TransportClient.builder().build()
    client.processList(batch)
}

当我应该这样做时:

for (batch in batches) {
    var client = TransportClient.builder().build()
    process_batch(batch, client)
}

def process_batch(batch, client) {
    client.processList(batch)
}

-4

首先,我不会过多地指责OS / VM ..而是编写代码的开发人员创建了很多线程。基本上在代码的某个地方(或第三方),很多线程都是在没有控制的情况下创建的

仔细检查stacktraces /代码并控制创建的线程数。通常,您的应用程序不需要大量线程,如果确实如此,那就是另一个问题。


10
这不是解决问题的方法。
ftrujillo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.