出现场景
最近在部署一个省的项目时,遇到这个问题,该环境提供的服务器配置偏低,而项目本身为了性能,大量的使用的线程,导出出现 java.lang.OutOfMemoryError: unable to create new native thread异常
异常分析
这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory JVM内存
ReservedOsMemory 保留的操作系统内存
ThreadStackSize 线程栈的大小
在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生 java.lang.OutOfMemoryError: unable to create new native thread
解决思路
- 如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
- 如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:
- MaxProcessMemory 使用64位操作系统
- VMMemory 减少 JVMMemory 的分配
- ThreadStackSize 减小单个线程的栈大小
解决方案
-
适当牺牲性能,优化代码里面的线程池的线程配置。
-
减少 JVMMemory 的分配
由于博主的项目是通过 Kubernetes 管理的,可以直接在对应的 yml 文件添加 jvm 的启动参数spec: containers: - image: dk.io/library/group-performance-service:0.0.8 env: - name: "JAVA_OPTIONS" value: "-Xms256m -Xmx512m -Xss1m" name: res-gather
重启工程后解决问题
后续
通过上述改动,程序在运行一段时间后,依然报内存溢出的错误!!!😱😱😱内心奔溃
没办法,接着分析错误原因
异常分析
上述都是在考虑线程的问题,线程又受到服务器进程的限制,难道是服务器上的进程数超最大限制了??😌😌😌
1.查看最大进程数 sysctl kernel.pid_max
2.查看当前进程数 ps -eLf | wc -l
观察发现有时后台定时任务启动的时候,当前进程数会超过系统的最大进程数限制!!!确认是进程数满了。
解决方案
1.修改最大进程数后系统恢复
echo 1000000 > /proc/sys/kernel/pid_max
2.永久生效
echo "kernel.pid_max=1000000 " >> /etc/sysctl.conf
sysctl -p
观察一段时间,服务器再也没有报内存溢出错误,问题解决 😊😊😊