咱們穿過山和大海,也見過人山人海。
咱們見過各種故障,也排過千雷萬險。
這一次,不如咱們一塊兒,開啓穩定性的探索之旅。
讓沒法解決的問題少一點點,讓世界的肯定性多一點點。html
不管是前端業務的開發者,仍是後端架構的開發者,都會遇到業務穩定性的難題。但穩定性的話題涉及之廣、之深,很難經過一兩篇文章道清原委。所以,咱們集結了多位阿里技術工程師,他們來自性能壓測、故障演練、JVM、應用容器、服務框架、流量調度、監控、診斷等不一樣的技術領域,以更結構化的方式來打造穩定性領域的知識庫,該知識庫的目錄將分爲:前端
但咱們也深知,僅憑阿里自身的業務場景和技術積累,很難知足各行業不一樣業務場景下對穩定性知識和經驗獲取的需求,所以,咱們將以開源的方式進行共建,歡迎您將本身或所在企業在穩定性方面的實踐分享給更多的人,讓沒法解決的問題少一點,讓世界的肯定性多一點:java
歡迎在文末,寫下你的留言,隨機抽3位,送出記念衫套裝( Polo 衫 & T恤,共計兩件)。linux
如下是來自『StabilityGuide』的第一篇文章:《系統穩定性——OutOfMemoryError 常見緣由及解決方法》。git
當 JVM 內存嚴重不足時,就會拋出 java.lang.OutOfMemoryError 錯誤。本文總結了常見的 OOM 緣由及其解決方法,以下圖所示。若有遺漏或錯誤,歡迎補充指正。github
若是對 JVM 內存模型和垃圾回收機制不熟悉,推薦閱讀 《我們從頭至尾說一次 Java 垃圾回收》。數據庫
當堆內存(Heap Space)沒有足夠空間存放新建立的對象時,就會拋出 java.lang.OutOfMemoryError: Java heap space 錯誤(根據實際生產經驗,能夠對程序日誌中的 OutOfMemoryError 配置關鍵字告警,一經發現,當即處理)。後端
Java heap space 錯誤產生的常見緣由能夠分爲如下幾類:數組
針對大部分狀況,一般只須要經過 -Xmx 參數調高 JVM 堆內存空間便可。若是仍然沒有解決,能夠參考如下狀況作進一步處理:緩存
當 Java 進程花費 98% 以上的時間執行 GC,但只恢復了不到 2% 的內存,且該動做連續重複了 5 次,就會拋出 java.lang.OutOfMemoryError:GC overhead limit exceeded 錯誤。簡單地說,就是應用程序已經基本耗盡了全部可用內存, GC 也沒法回收。
此類問題的緣由與解決方案跟 Java heap space 很是相似,能夠參考上文。
該錯誤表示永久代(Permanent Generation)已用滿,一般是由於加載的 class 數目太多或體積太大。
永久代存儲對象主要包括如下幾類:
PermGen 的使用量與加載到內存的 class 的數量/大小正相關。
根據 Permgen space 報錯的時機,能夠採用不一樣的解決方案,以下所示:
若是上述方法沒法解決,能夠經過 jmap 命令 dump 內存對象 jmap -dump:format=b,file=dump.hprof ,而後利用 Eclipse MAT 功能逐一分析開銷最大的 classloader 和重複 class。
JDK 1.8 使用 Metaspace 替換了永久代(Permanent Generation),該錯誤表示 Metaspace 已被用滿,一般是由於加載的 class 數目太多或體積太大。
此類問題的緣由與解決方法跟 Permgen space 很是相似,能夠參考上文。須要特別注意的是調整 Metaspace 空間大小的啓動參數爲 -XX:MaxMetaspaceSize。
每一個 Java 線程都須要佔用必定的內存空間,當 JVM 向底層操做系統請求建立一個新的 native 線程時,若是沒有足夠的資源分配就會報此類錯誤。
緣由分析
JVM 向 OS 請求建立 native 線程失敗,就會拋出 Unable to create new native thread,常見的緣由包括如下幾類:
該問題發生的常見過程主要包括如下幾步:
解決方案
ulimit -a .... 省略部份內容 ..... max user processes (-u) 16384
該錯誤表示全部可用的虛擬內存已被耗盡。虛擬內存(Virtual Memory)由物理內存(Physical Memory)和交換空間(Swap Space)兩部分組成。當運行時程序請求的虛擬內存溢出時就會報 Out of swap space? 錯誤。
緣由分析
該錯誤出現的常見緣由包括如下幾類:
解決方案
根據錯誤緣由能夠採起以下解決方案:
有一種內核做業(Kernel Job)名爲 Out of Memory Killer,它會在可用內存極低的狀況下「殺死」(kill)某些進程。OOM Killer 會對全部進程進行打分,而後將評分較低的進程「殺死」,具體的評分規則能夠參考 Surviving the Linux OOM Killer,詳情點擊這裏。
不一樣於其餘的 OOM 錯誤,Kill process or sacrifice child 錯誤不是由 JVM 層面觸發的,而是由操做系統層面觸發的。
緣由分析
默認狀況下,Linux 內核容許進程申請的內存總量大於系統可用內存,經過這種「錯峯複用」的方式能夠更有效的利用系統資源。
然而,這種方式也會無可避免地帶來必定的「超賣」風險。例如某些進程持續佔用系統內存,而後致使其餘進程沒有可用內存。此時,系統將自動激活 OOM Killer,尋找評分低的進程,並將其「殺死」,釋放內存資源。
解決方案
JVM 限制了數組的最大長度,該錯誤表示程序請求建立的數組超過最大長度限制。
JVM 在爲數組分配內存前,會檢查要分配的數據結構在系統中是否可尋址,一般爲 Integer.MAX_VALUE - 2。
此類問題比較罕見,一般須要檢查代碼,確認業務是否須要建立如此大的數組,是否能夠拆分爲多個塊,分批執行。
Java 容許應用程序經過 Direct ByteBuffer 直接訪問堆外內存,許多高性能程序經過 Direct ByteBuffer 結合內存映射文件(Memory Mapped File)實現高速 IO。
緣由分析
Direct ByteBuffer 的默認大小爲 64 MB,一旦使用超出限制,就會拋出 Direct buffer memory 錯誤。
解決方案
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。