unable to create new native thread问题定位

【错误信息】

java.lang.OutOfMemoryError: unable to create new native thread

【解决思路】

1、看到该异常后。首先,尝试打印堆栈(jstack PID),结果尽然打不出来,报如下错误

 

 

 2、这下问题不好定位了。查看具体线程数是多少(top -H -p PID),尽然有4000多个

 

3、查看了该服务器上可以启动的线程数(ulimit -u),发现线上数为4096,当前出问题的进程就占用了4013。

4、以上操作,发现对于当前定位,意义并不大,具体问题出在了哪里,还是没有找出来。于是,尝试了另外打印堆栈的方式(kill -3 PID),堆栈信息打印在了catalina.out日志中,发现堆栈中尽然有3000多个Timer线程。

 5、然后查看了业务逻辑中使用Timer的位置,会在任务不需调度时,通过Timer来定时调度。但是,每个任务就会起一个Timer,至于为啥会有这么多线程。查看了Timer的相关代码。

private void mainLoop() {
// 这里尽然是一个死循环
while (true) { try { TimerTask task; boolean taskFired; synchronized(queue) { // newTasksMayBeScheduled默认值时true, 同时无法更改 while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); // 也就是在queue为空,比如走到这个位置,这就解释了堆栈中为啥会处于WAITING状态 if (queue.isEmpty()) break; // Queue is empty and will forever remain; die // Queue nonempty; look at first evt and do the right thing long currentTime, executionTime; task = queue.getMin(); synchronized(task.lock) { if (task.state == TimerTask.CANCELLED) { queue.removeMin(); continue; // No action required, poll queue again } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime; if (taskFired = (executionTime<=currentTime)) { if (task.period == 0) { // Non-repeating, remove queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule queue.rescheduleMin( task.period<0 ? currentTime - task.period : executionTime + task.period); } } } if (!taskFired) // Task hasn't yet fired; wait queue.wait(executionTime - currentTime); } if (taskFired) // Task fired; run it, holding no locks task.run(); } catch(InterruptedException e) { } } }

6、基本逻辑出问题的点,基本理论上已经定位清楚。通过,按照理论推断,进行了复现。

7、修复的方式,是使用了共用的Timer(这里可能存在一个问题,就是内存抗不住,关于内存的问题,后续根据实际情况观察)

posted @ 2020-02-24 23:37  woniu4  阅读(9603)  评论(0编辑  收藏  举报