【JVM】OOMError之Unable to create new native thread

       最近线上出现了一个OOM的问题,使得服务异常以至于不可用。

一、现象

       从现象来看就是请求服务全部失败,线程数激增,cpu和内存显示相对正常。查看error.log,都是"error.log:unable to create new native thread"错误:

[ERROR] [org.springframework.boot.web.servlet.support.ErrorPageFilter:190] -- Forwarding to error page from request [/a/b/c/d/e/f] due to exception [unable to create new native thread]
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 sun.net.www.http.KeepAliveCache$1.run(KeepAliveCache.java:112)
        at sun.net.www.http.KeepAliveCache$1.run(KeepAliveCache.java:96)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.net.www.http.KeepAliveCache.put(KeepAliveCache.java:95)
        at sun.net.www.http.HttpClient.putInKeepAliveCache(HttpClient.java:407)
        at sun.net.www.http.HttpClient.finished(HttpClient.java:364)
        at sun.net.www.http.ChunkedInputStream.closeUnderlying(ChunkedInputStream.java:219)
        at sun.net.www.http.ChunkedInputStream.processRaw(ChunkedInputStream.java:455)
        at sun.net.www.http.ChunkedInputStream.readAheadNonBlocking(ChunkedInputStream.java:520)
        at sun.net.www.http.ChunkedInputStream.readAhead(ChunkedInputStream.java:611)
        at sun.net.www.http.ChunkedInputStream.available(ChunkedInputStream.java:725)
        at java.io.FilterInputStream.available(FilterInputStream.java:168)

很明显是说无法创建本地线程了。

 

二、分析

通过jstack来进行分析:

EndpointManagerSD update schedule : #4077 daemon prio=5 os_prio=5 tid=0x000007exxxx nid=xxxxx waiting on condition (xxxxxx)
java.lang.Thread.State: TIMED_WAITING(parking)
    at sun.misc.Unsafe.park(Native method)
    - parking to wait for <0x000000000xafa> (a java.util.concurrent.AbstractQueuedSynchronizer.java:xxxx)
    at java.util.concurrent.locks.LockSupport.parkNanos
    at 

发现大量线程处于:TIME_WAITING阶段,根据关键字可以定位到代码中的问题。

原因就是在生产的过程中一直在创建消息队列的producer客户端,producer.start()之后没有close。

public void sendMsg(String msg) {
    Producer producer = new Procuer();
    producer.send(msg);
}

producer是我们发送消费的客户端,包含一定的资源,如线程,网络连接等,使用前进行初始化,使用完后,shutdown释放资源。在我们的使用中,每一条消息创建一个producer,但是使用完后,没有shutdown释放资源,那么随着不断new Producer,就会不断创建新的线程而不释放推荐使用方式是,服务启动初始化producer,服务关闭时,释放资源,中间保持长连接复用

该问题发生的常见过程主要包括以下几步:

1.JVM 内部的应用程序请求创建一个新的 Java 线程;

2.JVM native方法代理了该次请求,并向操作系统请求创建一个 native 线程;

3.操作系统尝试创建一个新的native 线程,并为其分配内存;

4.如果操作系统的虚拟内存已耗尽,或是受到 32 位进程的地址空间限制,操作系统就会拒绝本次native 内存分配;

5.JVM将抛出 java.lang.OutOfMemoryError: Unable to create new native thread 错误。

能创建的线程数的具体计算公式如下:

(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads

MaxProcessMemory:指的是一个进程的最大内存

JVMMemory:JVM内存

ReservedOsMemory :保留的操作系统内存

ThreadStackSize:线程栈的大小

 

 

三、解决方案

1. 调用完之后将producer.close()。

public void sendMsg(String msg) {
    Producer producer = new Procuer();
    producer.send(msg);
    producer.close();
}

2.维持一个维持producer复用对象,使用ConcurrentHashMap来保存topic和producer引用。

3.通用方案:

a.如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。

b.如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数.

c.适当牺牲性能,优化代码里面的线程池的线程配置。

d.升级配置,为机器提供更多的内存;

e.降低Java Heap Space大小;

f.修复应用程序的线程泄漏问题;

g.限制线程池大小;

h.使用 -Xss 参数减少线程栈的大小;

i.调高 OS 层面的线程最大数:执行 ulimia -a 查看最大线程数限制,使用 ulimit -u xxx 调整最大线程数限制。

 

Author:忆之独秀

Email:leaguenew@qq.com

转载注明出处:https://blog.csdn.net/lavorange/article/details/103448504

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值