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

时间:2013-05-28 10:04:45

标签: java out-of-memory

我们正在"java.lang.OutOfMemoryError : unable to create new native Thread" 32k线程后的8GB RAM VM(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

15 个答案:

答案 0 :(得分:73)

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

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

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

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

答案 1 :(得分:10)

我在加载测试期间遇到了同样的问题,原因是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);`
  

根本原因:JVM在抛出此异常时   JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR(资源耗尽(表示内存   用尽))或JVMTI_RESOURCE_EXHAUSTED_THREADS(线程耗尽)。

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

分析了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)

答案 2 :(得分:8)

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

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

答案 3 :(得分:5)

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

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

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

OutOfMemoryError: unable to create new native thread – Problem Demystified

答案 4 :(得分:3)

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

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

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

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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

  1. 在其中运行的应用程序请求新的Java线程 JVM
  2. JVM本机代码代理创建新本机的请求 线程到操作系统操作系统尝试创建一个新的本机线程 需要将内存分配给线程
  3. 操作系统会拒绝 本机内存分配要么是因为32位Java进程大小 耗尽了其内存地址空间 - 例如(2-4)GB流程大小 限制已被命中 - 或操作系统的虚拟内存已完全 耗尽
  4. java.lang.OutOfMemoryError:无法创建新的本机 抛出线程错误。
  5. 参考:https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

答案 8 :(得分:0)

我遇到了同样的问题,结果却是对Java API的不当使用。我正在批量处理方法中初始化一个构建器,该方法不应该多次初始化。

基本上我做的是:

equals()

当我应该这样做时:

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

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

答案 9 :(得分:0)

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

ps huH

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

答案 10 :(得分:0)

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

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

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

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

所以问题可能出在内存中 要考虑的一点是

  

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

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

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

我在 centOS/Red Hat 机器上遇到了同样的问题。您已达到用户、进程或总体限制的线程数限制

就我而言,用户可以拥有的线程数是有限制的。可以检查,该行说最大用户进程

ulimit -a

您可以使用此命令查看正在运行的线程数

$ ps -elfT | wc -l

要获取您的进程正在运行的线程数(您可以使用 top 或 ps aux 获取您的进程 pid):

$ ps -p <PROCESS_PID> -lfT | wc -l

/proc/sys/kernel/threads-max 文件为线程数提供了系统范围的限制。 root 用户可以更改该值

要更改限制(在本例中为 4096 个线程):

$ ulimit -u 4096

您可以在此处找到有关 Red Hat/centOs 的更多信息 http://www.mastertheboss.com/jboss-server/jboss-monitoring/how-to-solve-javalangoutofmemoryerror-unable-to-create-new-native-thread

答案 13 :(得分:0)

您是否正在使用 system.d 启动您的 Java 应用程序?这是给你的!

我最近偶然发现了 DefaultTasksMax [1],由于某种原因它在我的机器上被限制为 60 - 不足以安装我的新 keycloak。

Keycloak 在达到“60”限制 (java.lang.OutOfMemoryError : unable to create new native Thread) 后立即崩溃并显示 ps -elfT | grep keycloak|wc -l

解决方案

1.查看您的 system.d 设置

systemctl show --property DefaultTasksMax

就我而言。这打印了 60

2.提供更高的价值

editor /etc/systemd/system.conf

编辑:

DefaultTasksMax=128

您也可以在您的单元文件中设置类似的值 TaskMax。见[2]。

3.重新加载、检查、重新启动

systemctl daemon-reload
systemctl show --property DefaultTasksMax
systemctl start keycloak

[1] https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html

[2] https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html

答案 14 :(得分:-4)

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

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