java.lang.OutOfMemoryError:无法创建新的本机线程-fs->;in_exec clone()和execve()冲突?

java.lang.OutOfMemoryError:无法创建新的本机线程-fs->;in_exec clone()和execve()冲突?,java,linux,multithreading,linux-kernel,out-of-memory,Java,Linux,Multithreading,Linux Kernel,Out Of Memory,我偶尔会遇到:- Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:691) 我已经读了很多关于这方面的书,我不认为我达到了一个真正的极限 物理内存、虚拟内存(64位JVM)、线程限制、进程限

我偶尔会遇到:-

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:691)
我已经读了很多关于这方面的书,我不认为我达到了一个真正的极限 物理内存、虚拟内存(64位JVM)、线程限制、进程限制或文件描述符

事实上,我甚至不确定这是否与我注意到受到影响的进程是Java进程这一事实有关

我怀疑这是Linux内核中的一个问题,或者可能取决于争论的方式,是Java JVM或pthread_create()中的一个问题

我在上面看到的机器是一个怪物:64个处理器,512GB内存(70GB免费)。 其运行的RHES 5.11(Tikanga)2.6.18-402.el5 x86_64。 限制是这样设置的

bash-3.2$ cat /proc/sys/kernel/pid_max
65536
bash-3.2$ cat /proc/sys/kernel/threads-max
8257699

bash-3.2$ /sbin/sysctl fs.file-nr
fs.file-nr = 62220      0       1048576

bash-3.2$ /sbin/sysctl fs.file-max
fs.file-max = 1048576

bash-3.2$ 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) 4128849
max locked memory   (kbytes, -l) 32
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) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4128849
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
许多用户使用这台计算机,到目前为止,只有两个用户(我和另一个)报告了这个问题。这些用户的共同点是,受影响的进程将定期创建Java线程 它会运行一段时间然后停止,而且还会有其他进程在同一个userid下定期和定期地调度。受害Java进程本身不执行任何其他进程

在我的例子中,Java进程定期建立JMX连接,使用它们,然后关闭它们,这涉及到在后台创建线程(这不在我的控制之下,所以我不能将其共享)。另一个活动是循环shell脚本,它运行一些进程,然后休眠,然后重复。进程数、每个进程的线程数、内存使用、文件描述符使用等都在一定范围内

在fork.c的实现中,可以返回EAGAIN的原因有很多,主要是资源或安全方面的原因(在这种情况下,我很难相信这一点),还有一个原因与copy\fs和fs->In\u exec有关。 当存在不安全的execve时,可以在check\u unsafe\u execve()中设置in\u exec,具体取决于共享结构fs\u struct的使用情况(我不太理解,请参见最后的注释)

本质上,似乎在clone()处理和execve()处理之间存在某种竞争条件或不幸的时间对齐,这可能导致clone()返回EAGAIN。 在我看来,这似乎是错误的,因为实际上并没有达到资源限制,而且对于clone(),每个手册页并没有“太多进程”

网上有关于这种行为是否必要或正确的讨论。

如果论点是,如果一个行为良好的程序从clone()接收到EAGAIN后应该重试,那么这是有问题的,因为程序如何区分由in_exec(它希望重试)引起的EAGAIN和真正的资源短缺(它可能不希望长时间重试)

我在Java7和Java8上看到了异常,我认为版本无关紧要,因此查看任何旧的OpenJDK源代码版本,我可以看到没有发生重试(os/linux/vm/os_linux.cpp)

另外,从strace,我可以看到JVM发出clone(),接收EAGAIN,然后死亡

1454948661.318678 clone(
    child_stack=0x2b6297dc5250,
    flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_
    parent_tidptr=0x2b6297dc59d0,
    tls=0x2b6297dc5940, child_tidptr=0x2b6297dc59d0
    ) = -1 EAGAIN (Resource temporarily unavaiable)
在这一点上,我不确定我正在寻找所使用内核的正确Linux内核源代码。 我也不明白fs_结构的用途,以及它如何在线程和进程之间共享。 所以在探索了极限之后,我正在研究另一种可能性,因为它是剩下的

如果我是对的,那么需要什么来故意造成问题呢。 我曾尝试编写启动大量pthread、fork和execve短期进程的程序,以增加clone()与execve()同时出现在Java中的可能性。我尝试了一些变化,但我不确定我是否成功地获得了正确的事件组合,或者说幸运。 这可能是因为我不完全理解获取“不安全”execve()意味着什么

什么是fs_结构,何时可以共享,我如何影响它

我的建议有意义吗


关于如何证明/反驳我的怀疑,有什么建议吗?

我想您首先需要了解有关受影响程序中线程创建的更多信息,特别是在OOM情况发生时存在多少线程?你确定你没有仅仅达到每个进程的线程数、每个用户的线程数、堆栈空间等操作系统限制吗?当我们遇到这个问题时,它总是由达到
/proc/sys/kernel/pid_max
限制引起的。你百分之百确定你没有击中这个吗?遇到问题时,您至少应该计算系统上的线程数。运行
ps-eL | wc-l
应该会显示系统上的线程总数。在限制范围内。从未见过总线程数超过30000,pid_max为65536。您的
/proc/sys/vm/overmit_内存
/proc/sys/vm/overmit_比率
设置是什么?您可能希望尝试将
/proc/sys/vm/overmit\u memory
设置为1(始终为overmit),以查看您的问题是否消失。如果它真的消失了,您可能应该返回初始设置并分别添加更多的交换空间。0和50,但我无法更改这些设置。