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

在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 上都尝试过

我们还尝试了 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/limit. 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
276210 次浏览

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

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

如果因为节点上的 OutOfMemory 而导致 Job 失败,您可以调整每个节点的 max map 和 reduce 以及 JVM 选项的数量。Java.opts (默认值为200Xmx)通常需要根据数据节点特定的硬件进行增加。

这个链接 可能会有帮助... 请检查

这不是一个内存问题,尽管异常名称强烈建议这样做,而是一个操作系统资源问题。您正在耗尽本机线程,即操作系统允许 JVM 使用多少个线程。

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

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

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

我还建议您查看一下线程堆栈大小,看看是否创建了更多的线程。对于 Linux 操作系统上的64位 VM,JRockit 1.5/1.6的默认线程堆栈大小为1MB。32K 线程将需要大量的物理和虚拟内存来满足这一要求。

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

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

无法创建新的本机线程-问题解密

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

仔细检查堆栈跟踪/代码,并控制创建的线程数量。通常情况下,你的应用程序不应该需要大量的线程,如果它这样做,这是一个不同的问题。

您的 JBoss 配置有一些问题, /opt/jrockit-jdk1.6/bin/java-Xms512m-Xmx512m Xms 和 Xmx 将 JBoss 的内存使用量限制在配置值之内,因此从8Gb 开始,服务器只使用了512M + 一些额外的内存来满足自己的需求,增加这个数字,记得给操作系统和其他运行在那里的东西留一些空闲空间,也许你可以让它运行起来,尽管有令人讨厌的代码。 如果可以的话,修复代码也不错。

我在负载测试中遇到了同样的问题,原因是 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 (线程耗尽)。

在我的例子中,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)

我也遇到过同样的问题,结果证明这是对 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)
}

每当 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. 无法创建新的本机 抛出线程错误。

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

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

对于我来说,它在使用 JPS列出所有 java 进程时解决了这个问题(只需在 shell 中执行 jps) ,并使用针对每个幽灵进程的 kill -9 pid bash 命令分别杀死它们。

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

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

ps huH

我通常会将输出重定向到一个文件,并脱机分析该文件(每个进程的线程数是否如预期的那样)

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

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

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

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

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

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

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

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

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

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

在我的例子中,用户可以拥有的线程数量是有限制的。可以用最大用户进程这一行来检查

ulimit -a

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

$ ps -elfT | wc -l

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

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

Proc/sys/kernel/thread-max 文件为线程数量提供了一个系统范围的限制

更改限制(在本例中为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的信息

你开始你的 java 应用程序与 System.d? 这是给你的!

我最近偶然发现了 DefaultTasksMax[1] ,由于某些原因,它在我的机器上被限制为60——对于我的新密钥斗篷安装来说不够。

钥匙斗篷与 java.lang.OutOfMemoryError : unable to create new native Thread崩溃尽快达到’60’限制(ps -elfT | grep keycloak|wc -l)。

解决方案

1. 查看 system. d 设置

systemctl show --property DefaultTasksMax

在我的情况下。这打印 60

2. 提供更高的价值

editor /etc/systemd/system.conf

编辑:

DefaultTasksMax=128

也可以在 Unit-File 中设置类似的值 TaskMax

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