jvm 为什么几天后会出现java.lang.OutOfMemoryError和pthread_create失败的情况?

tzxcd3kk  于 2022-11-07  发布在  Java
关注(0)|答案(2)|浏览(131)

我知道,这个问题听起来很模糊,但我试图理解和解决这个问题已经有一段时间了,也就是说,没有简单地自动重启pod(应用程序在K8中运行)定期。
在(Kotlin,Sping Boot )应用程序运行了几天之后,我突然得到了很多这样的两个:

  • Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 256k, guardsize: 0k, detached.
  • Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 256k, guardsize: 0k, detached.

监控截图:

其他信息:

  • ulimit -n1048576
  • 第一个月第四个月第一个月:第一个月第五个月
  • cat /proc/[...]/limits(使用我的进程ID):gist.github.com/Dobiasd/c6e38668b36f8eb97ff69e15a45cf635
  • cat /proc/sys/kernel/threads-max得到2060488
  • /etc/security/limits.conf为空(仅限#-注解行)
  • java -XX:+PrintFlagsFinal -version | grep -i thread看起来也不可疑:https://gist.github.com/Dobiasd/01623e9066889c8fd059bd387a15fafa
  • 堆栈大小(每个线程)减少到256 K(-Xss256K,默认值为1 M)。
  • 从运行正常的pod(即,在问题发生之前)进行线程转储(使用jcmd),已有约2k个线程:gist.github.com/Dobiasd/391488295e6ffd05ecc5134450cd723d-它们中的大多数都是ThreadPoolExecutors中的守护线程,正在等待工作。(用于BigQuery插入)。稍后可能会跳转到更多线程,因为在某些错误情况下,我正在重新示例化WriteStreams / JsonStreamWriters。不过,这应该没问题。过一段时间后,旧的示例应该被垃圾回收,线程也会死亡。2所以6 k线程应该只是暂时存在(如果一切正常的话)。3是的,当然,可能有一些方法可以避免这种情况,但是根据现有的限制,6 k线程仍然不应该是一个问题。

有什么想法可能是什么原因和/或如何修复它?
2022年6月1日更新:我现在实现了一个线程更少的解决方案,也避免了从~2k线程到~ 6 k线程的大跳跃,如上面的执行器图所示。这个解决方案帮助我解决了问题,但我对~ 6 k线程为什么太多的好奇心仍然存在。)

mrfwxfqh

mrfwxfqh1#

虽然cat /proc/sys/kernel/threads-max显示系统范围内允许2M线程,但也可能存在用户级限制。

$ cat /proc/sys/kernel/threads-max
127953
$ ulimit -u
63976

实际上,这个简单的测试程序可以创建31k线程:

public class Test {

        public static void main(String[] args) {
            for (int i = 0; i < 100000; ++i) {
                try {
                    new Thread(() -> {
                        try {
                            Thread.sleep(60000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }).start();
                } catch (Throwable e) {
                    System.out.println(i);
                    throw e;
                }
            }
        }
}

这比我们预期的ulimit -u结果要少。
首先,您应该检查容器中的ulimit -u

ovfsdjhp

ovfsdjhp2#

我不知道我是否正确地阅读了你的图表,但在这里:https://i.imgur.com/Jpdv2F4.png“文件描述符”图表显示“最大:1.0 Mil电流:1.0 Mil”所以看起来你已经达到了打开文件的最大数量限制。
通过ulimit -n检查命令行上的限制是值得的。你也可以检查进程限制cat /proc/$(pgrep java)/limits

相关问题