在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
这不是内存问题,即使异常名称强烈建议,但操作系统资源问题。您的本机线程已用完,即操作系统将允许JVM使用多少个线程。
这是一个不常见的问题,因为你很少需要这么多。你有很多无条件的线程产生线程应该但不完成?
如果可能的话,您可以考虑在Executor的控制下重写使用Callable / Runnables。有许多标准执行程序具有各种行为,您的代码可以轻松控制。
(线程数量有限的原因有很多,但从操作系统到操作系统各不相同)
要查找正在创建线程的进程,请尝试:
ps huH
我通常将输出重定向到文件并离线分析文件(每个进程的线程数是否符合预期)
由于以下两个原因,可能会出现此错误:
我怀疑线程的数量已经超过了java进程的限制
所以问题很可能是因为记忆问题需要考虑的一点
不在JVM堆中创建线程。它们是在JVM堆外部创建的。因此,如果RAM中剩余的空间较少,则在JVM堆分配之后,应用程序将遇到“java.lang.OutOfMemoryError:无法创建新的本机线程”。
可能的解决方案是减少堆内存或增加总体ram大小
如果jvm是通过systemd启动的,那么某些linux操作系统中可能存在每个进程限制的maxTasks(任务实际上意味着线程)。
您可以通过运行“服务状态”来检查这一点,并检查是否存在maxTasks限制。如果有,你可以通过编辑/etc/systemd/system.conf删除它,添加一个配置:DefaultTasksMax = infinity
首先,我不会责怪操作系统/虚拟机......而是编写代码的开发人员创建了很多线程。基本上在代码(或第三方)的某个地方,很多线程都是在没有控制的情况下创建的。
仔细查看stacktraces / code并控制创建的线程数。通常你的应用程序不需要大量的线程,如果这是一个不同的问题。
我在加载测试期间遇到了同样的问题,原因是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)
您的操作系统可能不允许您尝试创建的线程数,或者您在JVM中遇到了一些限制。特别是如果它是32k这样的整数,那么这种或那种极限很可能是罪魁祸首。
你确定你真的需要32k线程吗?大多数现代语言都对可重用线程池提供某种支持 - 我确信Java也有一些东西(比如用户Jesper提到的ExecutorService
)。也许您可以从这样的池中请求线程,而不是手动创建新线程。
我建议还要查看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
由于在bash中使用top时没有显示的ghost进程,我遇到了同样的问题。这阻止了JVM产生更多线程。
对我来说,它解决了使用jps列出所有java进程(只在shell中执行jps
)并使用kill -9 pid
bash命令为每个ghost进程单独杀死它们。
这可能在某些情况下有所帮助。
如果您的作业因节点上的OutOfMemmory而失败,您可以调整最大映射和缩减器的数量以及JVM的每个选项。 mapred.child.java.opts(默认值为200Xmx)通常必须根据您的数据节点特定硬件进行增加。
This link可能会有帮助...请检查
你的JBoss配置有一些问题,/ opt / jrockit-jdk1.6 / bin / java -Xms512m -Xmx512m Xms和Xmx正在限制你的JBoss内存使用,到配置的值,所以从8Gb你有服务器只有512M +为了他自己的目的而增加一些额外的东西,增加这个数字,记得留下一些免费的操作系统和其他运行的东西,可能你得到它运行尽管de令人讨厌的代码。如果可以的话,修复代码也会很好。
只要JVM从操作系统请求新线程,您就有机会面对java.lang.OutOfMemoryError: Unable to create new native thread
。只要底层操作系统无法分配新的本机线程,就会抛出此OutOfMemoryError。本机线程的确切限制非常依赖于平台,因此建议通过运行类似于以下链接示例的测试来找出这些限制。但是,总的来说,造成java.lang.OutOfMemoryError: Unable to create new native thread
的情况经历了以下几个阶段:
参考:https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread
我遇到了同样的问题,结果证明是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)
}