5. Unable to create new native thread

5.1 Unable to create new native thread

Java應用一般是多線程的. 這意味着在用Java寫的程序(似乎)可以在同時做多件事情. 例如 – 即使機器只有一個處理器 – 當你把內容從一個窗口拖動到另一個, 在後臺播放的電影不會停止因爲您一次執行了幾個操作.

思考線程的一種方法是將它們視爲可供提交任務的工作人員. 如果你只有一名員工, 他/她只能同時做一個任務. 但是當你有一打員工供你差遣, 他們可以同時完成你的幾個要求.

現在, 就像在現實世界的員工, 在JVM裏的線程也需要一些空間來開展他們被傳喚去要處理的工作. 當線程數超過了這個內存空間的限制的時候, 我們就會碰到下邊的問題:

這個消息:java.lang.OutOfMemoryError: Unable to create new native thread 意味着Java應用已經達到它可以運行的線程數的上限.

5.2 原因

只要JVM向OS申請新線程, 你都有機會碰到java.lang.OutOfMemoryError: Unable to create new native thread. 只要下面的OS不能再分配一個新的native thread, 這個OutOfMemoryError會被拋出. 準確的native thread限制與對應的平臺有關, 因此, 我們推薦通過運行下面的例子來找到這個限制. 但是, 通常, 引發java.lang.OutOfMemoryError: Unable to create new native thread會經過下列階段:

  1. 運行在JVM裏的一個應用請求一個新的Java線程
  2. JVM native代碼傳遞要創建一個新的native 線程到OS
  3. OS嘗試創建一個新的native 線程, 同時需要分配內存給這個線程
  4. OS將會拒絕本地內存分配, 可能是因爲32-bit Java進程大小已經耗盡了它的內存地址區域 – 如: 達到了2-4GB的進程大小限制 – 或是這個OS的虛擬內存已經被耗盡
  5. 拋出java.lang.OutOfMemoryError: Unable to create new native thread錯誤.

5.3 示例

下列例子循環啓動和創建新的線程. 當運行這段代碼, 操作系統會迅速達到限制, 顯示出java.lang.OutOfMemoryError: Unable to create new native thread消息.

while (true) {
    new Thread(new Runnable()) {
        public void run() {
            try {
                Thread.sleep(10000000);
            } catch (InterruptedException e) { }
        }
    }}.start();
}

確切的native thread限制與平臺有關, 如在Windows, Linux和Mac OS X上測試結果如下:
- 64-bit Mac OS X 10.9, Java 1.7.0_45 – JVM在創建2031個線程後死掉
- 64-bit Ubuntu Linux, Java 1.7.0_45 – JVM在創建31893個線程後死掉
- 64-bit Windows 7, Java 1.7.0_45 – 因爲這個OS使用了一個不同的線程模型, 在這個平臺上似乎沒有拋出該錯誤. 在線程達到250,000後, 進程仍然存活, 儘管swap區已經使用了10GB, 同時應用面臨非常嚴重的性能問題.

所以, 在引入一個小測試時前, 確保你知道你的電腦的限制, 來發現什麼時候java.lang.OutOfMemoryError: Unable to create new native thread會被觸發.

5.4 解決方案

有時候, 你可以通過增加OS層面的限制來繞過這個Unable to create new native thread問題. 例如, 如果你限制了JVM在 user space可以生成的max user processes, 那麼你應該檢查並嘗試增大這個限制:

[root@dev ~]# ulimit -a
core file size          (blocks, -c) 0
--- cut for brevity ---
max user processes              (-u) 1800

通常情況下,因爲本機達到線程的限制而拋出OutOfMemoryError錯誤提示可能表明有編程錯誤. 當你的應用生成了上千個線程, 很有可能有些地方出了大問題 – 沒有太多的應用程序可以從如此大量的線程中獲益(線程過多, 過猶不及)。

解決這個問題的一個辦法是做線程快照(thread dump)來理解這個場景. 你可能會花費好幾天做這個事情. 這時候, 聯繫我就是最好的方式(@ ̄ー ̄@).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章