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

问题描述 投票:109回答:13

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

但是,"top" and "free -m" shows 50% free memory available。 JDk是64位,并尝试使用HotSpot和JRockit.Server有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
java out-of-memory
13个回答
74
投票

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

这是一个不常见的问题,因为你很少需要这么多。你有很多无条件的线程产生线程应该但不完成?

如果可能的话,您可以考虑在Executor的控制下重写使用Callable / Runnables。有许多标准执行程序具有各种行为,您的代码可以轻松控制。

(线程数量有限的原因有很多,但从操作系统到操作系统各不相同)


0
投票

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

ps huH

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


0
投票

由于以下两个原因,可能会出现此错误:

  • 内存中没有空间容纳新线程。
  • 线程数超出操作系统限制。

我怀疑线程的数量已经超过了java进程的限制

所以问题很可能是因为记忆问题需要考虑的一点

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

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


0
投票

如果jvm是通过systemd启动的,那么某些linux操作系统中可能存在每个进程限制的maxTasks(任务实际上意味着线程)。

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


-4
投票

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

仔细查看stacktraces / code并控制创建的线程数。通常你的应用程序不需要大量的线程,如果这是一个不同的问题。


11
投票

我在加载测试期间遇到了同样的问题,原因是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耗尽了线程以及内存(每个线程都保留内存,因为每个线程都被阻塞,所以没有释放内存)。

分析了java线程转储,观察到近61K线程被我们的一个方法阻塞,这就是造成这个问题的原因。下面是Thread转储的一部分

"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)

8
投票

您的操作系统可能不允许您尝试创建的线程数,或者您在JVM中遇到了一些限制。特别是如果它是32k这样的整数,那么这种或那种极限很可能是罪魁祸首。

你确定你真的需要32k线程吗?大多数现代语言都对可重用线程池提供某种支持 - 我确信Java也有一些东西(比如用户Jesper提到的ExecutorService)。也许您可以从这样的池中请求线程,而不是手动创建新线程。


6
投票

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

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

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

OutOfMemoryError: unable to create new native thread – Problem Demystified


3
投票

由于在bash中使用top时没有显示的ghost进程,我遇到了同样的问题。这阻止了JVM产生更多线程。

对我来说,它解决了使用jps列出所有java进程(只在shell中执行jps)并使用kill -9 pid bash命令为每个ghost进程单独杀死它们。

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


1
投票

如果您的作业因节点上的OutOfMemmory而失败,您可以调整最大映射和缩减器的数量以及JVM的每个选项。 mapred.child.java.opts(默认值为200Xmx)通常必须根据您的数据节点特定硬件进行增加。

This link可能会有帮助...请检查


1
投票

你的JBoss配置有一些问题,/ opt / jrockit-jdk1.6 / bin / java -Xms512m -Xmx512m Xms和Xmx正在限制你的JBoss内存使用,到配置的值,所以从8Gb你有服务器只有512M +为了他自己的目的而增加一些额外的东西,增加这个数字,记得留下一些免费的操作系统和其他运行的东西,可能你得到它运行尽管de令人讨厌的代码。如果可以的话,修复代码也会很好。


1
投票

只要JVM从操作系统请求新线程,您就有机会面对java.lang.OutOfMemoryError: Unable to create new native thread。只要底层操作系统无法分配新的本机线程,就会抛出此OutOfMemoryError。本机线程的确切限制非常依赖于平台,因此建议通过运行类似于以下链接示例的测试来找出这些限制。但是,总的来说,造成java.lang.OutOfMemoryError: Unable to create new native thread的情况经历了以下几个阶段:

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

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


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)
}
© www.soinside.com 2019 - 2024. All rights reserved.