linux当前用户最大进程数上限 导致java堆溢出
- 此文使用user表示Linux用户名
这种堆溢出是在启动线程时抛出。异常信息为unable to create new native thread
栈如下:
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:717)
at jdk.nashorn.internal.scripts.Script$1$\^shell\_.:program(<shell>:1)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
at jdk.nashorn.internal.runtime.Context.eval(Context.java:738)
at jdk.nashorn.internal.runtime.Context.eval(Context.java:673)
at jdk.nashorn.tools.Shell.readEvalPrint(Shell.java:516)
at jdk.nashorn.tools.Shell.run(Shell.java:168)
at jdk.nashorn.tools.Shell.main(Shell.java:143)
at jdk.nashorn.tools.Shell.main(Shell.java:119)
触发原理,在linux操作系统中,创建足够多线程,使当前用户在当前会话的子进程数量达到上限,再创建新线程便可触发。
查看和设置当前用户最大进程数
查看 ulimit -a
执行结果如下:
[user@localhost ~]$ 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) 190703
max locked memory (kbytes, -l) 16384
max memory size (kbytes, -m) unlimited
open files (-n) 40960
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) 40960
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimite
-a
即查看所有限制项。单独查看当前用户最大进程数则是 ulimt -u
给当前用户设置的上限的方法,直接在命令行上执行 ulimit -u 10000
。当前用户在命令行的方式设置的值只能小于等于设置之前的值。设置完立即生效,只影响当前会话。
也可以通过root用户修改 /etc/security/limits.conf 中 用户 nproc 项 根据其中注释样例和已有配置即可。(在CentOs和eulerosv2r7.x86_64 会有一个单独的 /etc/security/limits.d/20-nproc.conf文件,用来配置nproc,非root用户默认4096。修改文件的设置方法会在用户重新登录后生效。)
触发方法
-
查看最大进程数
ulimit -u
,统计已创建的子进程数,ps -efL | grep 当前用户名 | wc -l
user@localhost:~> ulimit -u 40960 user@localhost:~> ps -efL | grep user| wc -l 679
-
根据上述查询结果设置一个较小容易达到的上限,当前已创建679,将上限降低更容易复现,此处将当前会话的最大进程数设置为1000
ulimit -u 1000
-
可以使用java代码用循环创建线程即可,此处为了省去编译,采用jre目录下的jjs程序代替java。
检查jre/bin目录有没有在path中,没有则
export PATH=$PATH:/${jrePath}/bin
,后执行jjs会打印一个类似于python或者 nodejs交互式命令行
user@localhost:~> jjs jjs>
往交互式命令行输入,以下两行js语句,用来循环创建线程。(触发前最好新开一个ssh会话)
输入以下语句后回车。
//直接将类名赋值给变量即可 Th = java.lang.Thread //当前语句在jjs交互式命令行,需要单行输入 for (var i = 0; i < 400; i++) { new Th(function () { print(Th.currentThread().getName());Th.sleep(500000); }).start(); }
不出意外会发生堆溢出,且当前会话的终端无法继续交互,待休眠结束,线程释放终端可以被释放。
本文地址:https://blog.csdn.net/qq_26700087/article/details/108867434