记录一次内存溢出异常的排查和处理

1.问题描述

 测试在测试环境部署项目之后,发现后台有java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached 异常
 通过分析 该异常属于虚拟机栈和本地方法栈的内存溢出,出现该问题的请况有两种,一种是创建线程过多,另一种是线程数量不多但是内存空间不足。

2.根据问题进行排查

1.根据错误提示: unable to create native thread 说明是无法创建线程了,
出现原因有两个:
	1.系统内存耗尽,无法创建新的线程
	2.创建线程数超过了操作系统的限制
2.先排查一下是否是线程数超过了操作系统的限制
	1.查看出现问题的Java程序线程数量
	ps aux | grep java | grep -v grep | awk '{
    
    print $2, $NF}' | while read line
	 do 
	    pid=$(echo $line| awk '{
    
    print $1}')
	    pidname=$(echo $line| awk '{
    
    print $2}')
	    pid_count=$(ps huH p ${
    
    pid} | wc -l)
	    echo "pid: ${pid}    线程数: ${pid_count}    jar: ${pidname}"
	 done
	 执行该脚本可以输出Java进程创建线程的数量
		pid: 3369    线程数: 55    jar: com.**
		pid: 4270    线程数: 73    jar: com.**
		pid: 6846    线程数: 45    jar: com.**
		pid: 7035    线程数: 60    jar: com.**
		pid: 7263    线程数: 54    jar: com.**
		pid: 10996    线程数: 351    jar: com.**
		pid: 11067    线程数: 68    jar: com.**
		pid: 14263    线程数: 79    jar: com.**
		pid: 18647    线程数: 50    jar: com.**
		pid: 20211    线程数: 61    jar: com.**
		pid: 23411    线程数: 77    jar: com.**
		pid: 30247    线程数: 106    jar: com.**
	2.查看操作系统对的线程数创建的限制 ulimit -u 发现创建的线程数没有超过限制,
	那接下来就需要考虑服务器内存的问题
2.考虑服务器内存问题
	1.堆大小:线程所使用的内存,并不在Java堆中分配。因此,即使Java堆空间是充足的,如果剩余的物理内存太小,无法满足更多线程创建所需的内存时,也会抛出该异常。
	比如:服务器的物理内存为 6G。Java堆大小为 5G Heap + 512M Perm Gen,共占用 5.5G。那么,剩余的物理内存仅为 6-5.5=0.5G。而这 0.5G 的内存空间,将用于运行内核进程,以及其他的用户进程。Java虚拟机进程本身其实也会占用一部分的内存。显然,除去这些进程所占用的内存,剩下的空间已经很有限。在无法满足更多线程创建所需的内存时,将会抛出该异常。在不影响Java进程的情况下,可以考虑减少Java堆内存的分配,从而腾出更多的空间用于创建线程
	2.进程数太多:最大化的利用服务器的资源,提高资源的利用率,避免浪费资源。
于是,在一台服务器上部署了多个进程。可能由于进程数创建过多,或者进程内存不够扩大之后,导致物理机所剩的内存不多。从结果上看,与进程的堆大小占用内存过多是类似的,解决方法比较简单,就是减少服务器运行的进程数,将进程迁移到其他服务器
	3.既然每一个线程都需要占用一定的内存,那有没有办法给线程分配小一点内存呢?对于不同的Java虚拟机版本,有一个默认的线程栈大小。早期默认大小为256K,现在一般为1M。通过JVM-Xss 参数,可以调整该内存大小。假设我们要创建500个线程。如果每个线程需要1M内存,那么线程占用的总内存为500M。如果线程栈设置为512K,那么线程占用的内存将减少一半,为250M。需要注意的是,如果线程栈设置得过小,当线程请求分配的栈容量不足时,将会抛出StackOverflowError异常

3.分析原因解决问题

	通过对以上请况的判断,发现测试环境出现的问题是因为部署的测试服务太多,导致内存不足,解决办法只能是申请更多内存.

4.总结

当遇到java.lang.OutOfMemoryError:unable to create new native thread异常时,可以通过监控在OOM之前,服务器剩余内存、进程创建的线程数以及 ulimit -u 的结果进行综合排查解决。
同时,可以通过 jstack -l 将线程栈dump下来。进一步分析具体是哪里创建了线程,是否合理。
原因分析及6种解决方案:
	1.创建了过多的线程:减少线程数;
	2.操作系统对线程数的限制:调大线程数限制;
	3.服务器内存不足:增加物理内存;
	4.进程的堆内存太大:减小堆内存大小;
	5.服务器的进程数太多:减少进程数;
	6.线程栈的太大:调小线程栈。

猜你喜欢

转载自blog.csdn.net/qq_36488864/article/details/132097748