148

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

然而,"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
4

15 回答 15

92

即使异常名称高度暗示,这也不是内存问题,而是操作系统资源问题。您正在用完本机线程,即操作系统将允许您的 JVM 使用多少线程。

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

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

(线程数受限的原因有很多,但因操作系统而异)

于 2013-05-28T10:22:26.303 回答
15

我在负载测试期间遇到了同样的问题,原因是因为 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 线程被我们的一种方法阻塞,这导致了这个问题。下面是线程转储的部分

"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)
于 2015-12-22T00:45:31.107 回答
10

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

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

于 2019-04-10T06:45:30.083 回答
9

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

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

于 2013-05-28T10:13:40.750 回答
7

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

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

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

OutOfMemoryError: 无法创建新的本地线程 – 问题揭秘

于 2013-08-28T13:39:36.100 回答
4

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

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

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

于 2017-07-25T14:15:17.867 回答
3

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

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

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

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

所以问题可能是因为内存要考虑的一点是

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

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

于 2019-01-10T06:13:52.070 回答
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 本机代码向操作系统代理创建新本机线程的请求 操作系统尝试创建一个新的本机线程,该线程需要为线程分配内存
  3. 操作系统将拒绝本机内存分配,因为 32 位 Java 进程大小已耗尽其内存地址空间 - 例如 (2-4) GB 进程大小限制已达到 - 或操作系统的虚拟内存已完全耗尽
  4. 抛出 java.lang.OutOfMemoryError: Unable to create new native thread 错误。

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

于 2016-10-02T17:50:23.760 回答
2

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

ps huH

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

于 2018-02-16T18:54:49.117 回答
1

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

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

于 2013-05-28T10:13:58.777 回答
1

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

于 2014-03-06T22:06:53.307 回答
0

您是否使用 system.d 启动您的 java 应用程序?这个给你!

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

Keycloak 一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。见[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

于 2021-06-24T07:24:52.083 回答
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

于 2021-03-04T19:19:51.003 回答
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)
}
于 2016-06-14T01:15:15.697 回答
-5

首先,我不会过多地责怪 OS/VM .. 而是编写创建如此多线程的代码的开发人员。基本上在您的代码(或第 3 方)的某个地方,许多线程是在不受控制的情况下创建的

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

于 2013-10-18T09:16:48.763 回答