java.lang.OutOfMemoryError- unable to create new native thread 问题排查
2023/4/14 1:22:10
本文主要是介绍java.lang.OutOfMemoryError- unable to create new native thread 问题排查,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
问题描述
最近连续两天大约凌晨3点,线上服务开始异常,出现OOM报错。且服务所在的物理机只能ping通,但是无法登录。报错信息如下:
ERROR 04-12 03:01:43,930 [DefaultQuartzScheduler_Worker-3] JobRunShell[JobRunShell]:211 Job threw an unhandled Exception: java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:714) at java.util.concurrent.ForkJoinPool.createWorker(ForkJoinPool.java:1483) ... at org.quartz.core.JobRunShell.run(JobRunShell.java:202) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
排查过程
根据日志OOM报错,怀疑是内存不足或内存泄露的原因,需要查看内存的使用情况。考虑到JConsole
或VisualVM
具有可视化界面,能看出历史变化趋势,更直观地排查问题,因此为程序配置了jmx参数。重启应用,使用VisualVM
连接应用的jmx端口。应用配置jmx端口的参数如下:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=9998
VisualVM
显示使用的内存是正常的,没有持续飙升。但是线程数却比较异常,随时间推移在持续增加。因此考虑看看是什么线程在持续增加,jstack
是一个比较好用的工具,它用于生成 JAVA 虚拟机当前时刻的线程快照。
使用jstack -F PID
打印出了所有线程,发现有大片下面的堆栈信息。注意到com.xxx.http.IdleConnectionMonitorThread.run() @bci=15, line=22 (Compiled frame)
方法出现的特别多。
Thread 7760: (state = BLOCKED) - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise) - java.util.concurrent.ForkJoinPool.awaitWork(java.util.concurrent.ForkJoinPool$WorkQueue, int) @bci=354, line=1821 (Compiled frame) - java.util.concurrent.ForkJoinPool.runWorker(java.util.concurrent.ForkJoinPool$WorkQueue) @bci=44, line=1690 (Compiled frame) - java.util.concurrent.ForkJoinWorkerThread.run() @bci=24, line=157 (Compiled frame) Thread 7759: (state = BLOCKED) - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise) - com.xxx.http.IdleConnectionMonitorThread.run() @bci=15, line=22 (Compiled frame) - java.lang.Thread.run() @bci=11, line=745 (Compiled frame) Thread 7758: (state = BLOCKED) - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise) - com.xxx.http.IdleConnectionMonitorThread.run() @bci=15, line=22 (Compiled frame) - java.lang.Thread.run() @bci=11, line=745 (Compiled frame)
在项目搜索类IdleConnectionMonitorThread
,并查看22行内容。发现如果不执行shutdown()
方法,那么该后台线程会持续地执行wait()
方法,导致该线程不退出。实际情况是确实没有执行shutdown()
方法,随着每10分钟执行一次计算任务,每次计算任务会执行一批http请求,每个http请求就会创建出一个后台线程,这样会导致线程数越来越多。
联系了sdk的提供方,提供了后台进程的停止方法。在程序请求http完成后,释放请求的资源,停止了后台线程。使用VisualVm
观察了一段时间,发现线程数不在增长了,未出现OOM报错。至此问题解决。
虽然问题解决了,不过还有个疑问,线程数达到多少会触发unable to create new native thread
报错。查阅博客了解到,一个进程最多能创建多少线程是受多因素影响的,基本上是系统支持的最大PID、用户可创建最大线程数、系统支持的最大线程数的最小值。通过查看服务器配置,系统支持的最大PID的值是最小的:32768,也就是说一个进程最多创建大约3w个线程。由于服务器上部署了线上服务,不方便在复现验证创建多少个线程时出现OOM报错。
java.lang.OutOfMemoryError: unable to create new native thread问题排查以及当前系统最大进程数量
一个JVM可以创建多少线程,首先由JVM设置决定(-Xms,-Xmx,-Xss),另外受到外部因素影响,就是系统设置(最大PID、最大线程、栈内存大小、最重要的还是物理内存由多少)、其二就是用户设置(用户可以运行多少个进程或线程),综合上述因素的最小值就是一个JVM可以创建多少线程。
系统支持的最大进程数 cat /proc/sys/kernel/pid_max 32768 系统支持的最大线程数 cat /proc/sys/kernel/threads-max 513024 进程可用最大虚拟内存 ulimit -v unlimited 最大栈大小 ulimit -s 8192 每个用户可创建最大进程数 ulimit -u 256512
总结
1.JConsole
或VisualVM
具有可视化界面,可以方便地查看CPU占用、内存使用、类数量、线程数的历史变化趋势。
2.jstack
命令可以查看正在运行的程序当前时刻的所有线程信息。
3.一个进程最多能创建多少线程,是受多因素影响的,基本上是系统支持的最大PID、用户可创建最大线程数、系统支持的最大线程数的最小值。
参考资料
- java.lang.OutOfMemoryError: unable to create new native thread(CSDN)
- java.lang.OutOfMemoryError: unable to create new native thread问题排查以及当前系统最大进程数量
- java.lang.OutOfMemoryError: unable to create new native thread(简书)
这篇关于java.lang.OutOfMemoryError- unable to create new native thread 问题排查的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-01为什么公共事业机构会偏爱 TiDB :TiDB 数据库在某省妇幼健康管理系统的应用
- 2024-04-26敏捷开发:想要快速交付就必须舍弃产品质量?
- 2024-04-26静态代码分析的这些好处,我竟然都不知道?
- 2024-04-26你在测试金字塔的哪一层?(下)
- 2024-04-26快刀斩乱麻,DevOps让代码评审也自动起来
- 2024-04-262024年最好用的10款ER图神器!
- 2024-04-2203-为啥大模型LLM还没能完全替代你?
- 2024-04-2101-大语言模型发展
- 2024-04-17基于SpringWeb MultipartFile文件上传、下载功能
- 2024-04-14个人开发者,Spring Boot 项目如何部署