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(這里可能存在一個問題,就是內存抗不住,關於內存的問題,后續根據實際情況觀察)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM