我还有一个Java线程限制问题,但我只谈论微不足道的500个线程左右,我找不到我达到的限制。事实上 - 它似乎发生在 503 个线程的限制下,即看起来创建线程 504 会产生可怕的:
javax.ws.rs.ProcessingException: java.lang.OutOfMemoryError: unable to create new native thread
at org.glassfish.jersey.client.JerseyInvocation.submit(JerseyInvocation.java:980) [jersey-client-2.25.jar:na]
at org.glassfish.jersey.client.JerseyInvocation.submit(JerseyInvocation.java:889) [jersey-client-2.25.jar:na]
at org.glassfish.jersey.client.JerseyInvocation$AsyncInvoker.method(JerseyInvocation.java:669) [jersey-client-2.25.jar:na]
环境详情:
- AWS t2.medium EC2 实例。
- Java(TM) SE 运行时环境(内部版本 1.8.0_111-b14),使用 Java HotSpot(TM) 64 位服务器虚拟机(内部版本 25.111-b14,混合模式)。也转载于更新 u211。
- 使用 SLES 15。
- 测试服务器上有 4 GB
- 在生产服务器上看到类似的结果,该服务器是 t2.large EC2 实例 (8GB RAM)。
ulimit -a
输出:
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 15743
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 15743
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
观察:
- 似乎是网络 IO 线程导致了此问题。有许多线程池负责处理应用程序逻辑的各种位,它们很好。只是在执行大量网络I/O时,会创建更多的线程(取决于负载),这就是问题出现的时候。
- 应用程序的限制似乎是 503 个线程(如 VisualVM 和 JConsole 报告的那样)。如果我们加载测试并保持在 503 线程以下,一切正常。如果我们达到 503 个线程,则会收到 OOM 消息,并且不会创建更多线程。这远远低于在SO上出现的类似问题中出现的正常线程/进程限制。此外,在某些线程泄漏情况下,我们不会创建 1000 个线程。我们确实在尝试有意创建> 503 线程。
-Xss
设置为默认值 (1MB)、512k
和2M
时可重现 - 所有变体最高为 503 个线程,即这似乎不是物理内存限制,而是一些计数器限制。top
报告的内存使用量不超过 ~70%。
我可以提供线程转储和 NMT 输出,但它们似乎没有显示任何异常。它们只显示 503 个现有线程和堆分配等。
我看到的所有问题都与以下方面有关:
- 实际、错误的螺纹泄漏或
- 具有 1000 个线程的合法情况,
- 相当小的
ulimit
值。
这些都不适用于我的情况。
我确实看到了这个问题,它似乎表明某些晦涩的设置实际上覆盖/施加的限制小于使用ulimit
显示的限制,但问题和链接是关于 RedHat 的。SLES 的某个地方有类似的设置吗?
基本上我想知道 - 发生了什么?为什么我无法创建第 504 个线程?
事实证明这是一个系统问题。
systemd 引入了对单个进程的线程数限制,默认为 512 个线程。我认为我们在测试中的 503 限制实际上是
503 counted threads
+ 9 other threads not counted
= 512 thread limit.
在/etc/systemd/system.conf
中设置DefaultTasksMax=infinity
解决了这个问题(这确实需要重新启动我们的盒子)。
我们实际上正在运行一个initd服务,该服务通过systemctl在systemd上得到支持。这意味着我们不能只为我们的服务设置不同的限制,而必须为所有服务设置全局限制。