性能文章>OutOfMemoryError之unable to create new native thread原因分析及6种解决方案>

OutOfMemoryError之unable to create new native thread原因分析及6种解决方案原创

4年前
13073410

java.lang.OutOfMemoryError:unable to create new native thread 是比较常见的一种异常,表示应用程序无法创建新的线程。

产生该异常,总体上可总结为两个原因:

  1. 服务器剩余内存不足;
  2. 线程数超过系统限制。

问题定位与解决方案

通过分析异常可能产生的原因,可以通过选择以下合适的方案进行排查解决。

1. 是否创建了过多的线程

如果有对进程的线程数进行监控,可以查看线程创建的趋势,以及当前已创建的线程数,确认线程数是否合理。

同时,可以通过 jstack -l 将线程栈dump下来。线程栈的作用,一方面如果没监控可以用来检查已创建的线程数,另一方面可以可以通过分析栈的调用关系,确定是哪里在创建线程。

这里,有两个比较好的分析工具,一个是广为人知的 http://fastthread.io/ ,另一个是新秀 https://www.perfma.com/product/thread

通过这些工具,可以比较直观的看到线程的整体创建情况,例如普通线程、守护线程的数量与占比,各个状态的线程数量等。

2. 操作系统对线程数的限制

操作系统对线程数的创建是有限制的,这个限制可以通过 ulimit -u 来查看。

如果应用程序创建的线程数,超过了系统限制的最大线程数,也会抛出 unable to create new native thread 异常。

如果遇到了这种情况,通过适当的调大该值,可以解决问题。

如果要临时修改这个限制,可以通过执行 ulimit -u 65536 进行调整。

更好的方式,是将 ulimit -u 65536 写到启动脚本中,如 ~/.bashrc 或其他启动脚本。这样就不用每次都去手工修改了。

3. 服务器内存不足

如果用户创建的线程数在合理的范围内,也没有超过 ulimit -u 设置的值。

那么,为了确保能够正确的创建新的线程,可以考虑增加服务器的物理内存。

4. 进程的堆大小

需要注意的是,线程所使用的内存,并不在Java堆中分配。

因此,即使Java堆空间是充足的,如果剩余的物理内存太小,无法满足更多线程创建所需的内存时,也会抛出该异常。

一个例子:

假设服务器的物理内存为 6G。

Java堆大小为 5G Heap + 512M Perm Gen,共占用 5.5G。

那么,剩余的物理内存仅为 6-5.5=0.5G。

而这 0.5G 的内存空间,将用于运行内核进程,以及其他的用户进程。Java虚拟机进程本身其实也会占用一部分的内存。

显然,除去这些进程所占用的内存,剩下的空间已经很有限。

在无法满足更多线程创建所需的内存时,将会抛出该异常。

在不影响Java进程的情况下,可以考虑减少Java堆内存的分配,从而腾出更多的空间用于创建线程。

5. 服务器的进程数

我们通常希望能够最大化的利用服务器的资源,提高资源的利用率,避免浪费资源。

于是,在一台服务器上部署了多个进程。

可能由于进程数创建过多,或者进程内存不够扩大之后,导致物理机所剩的内存不多。

从结果上看,与进程的堆大小占用内存过多是类似的。

解决方法比较简单,就是减少服务器运行的进程数,将进程迁移到其他服务器。

6. 线程栈的大小

既然每一个线程都需要占用一定的内存,那有没有办法给线程分配小一点内存呢?

对于不同的Java虚拟机版本,有一个默认的线程栈大小。

早期默认大小为256K,现在一般为1M。

通过JVM的 -Xss 参数,可以调整该内存大小。

假设我们要创建500个线程。

如果每个线程需要1M内存,那么线程占用的总内存为500M。

如果线程栈设置为512K,那么线程占用的内存将减少一半,为250M。

需要注意的是,如果线程栈设置得过小,当线程请求分配的栈容量不足时,将会抛出StackOverflowError异常。

小结

总体上,当遇到java.lang.OutOfMemoryError:unable to create new native thread异常时,可以通过监控在OOM之前,服务器剩余内存、进程创建的线程数以及 ulimit -u 的结果进行综合排查解决。

同时,可以通过 jstack -l 将线程栈dump下来。进一步分析具体是哪里创建了线程,是否合理。

原因分析及6种解决方案:

  1. 创建了过多的线程:减少线程数;
  2. 操作系统对线程数的限制:调大线程数限制;
  3. 服务器内存不足:增加物理内存;
  4. 进程的堆内存太大:减小堆内存大小;
  5. 服务器的进程数太多:减少进程数;
  6. 线程栈的太大:调小线程栈。

本文翻译总结自:
https://dzone.com/articles/troubleshoot-outofmemoryerror-unable-to-create-new

点赞收藏
betterlife
请先登录,查看4条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

日常Bug排查-集群逐步失去响应

日常Bug排查-集群逐步失去响应

浅析AbstractQueuedSynchronizer

浅析AbstractQueuedSynchronizer

10
4