使用 AIX IBM HeapAnalyzer 查詢 Java OOM 問題
最近接的案子有遇到 Java OOM。這種問題最麻煩的地方在於,看到 OutOfMemoryError 不代表你立刻就知道是哪一段程式出了問題。很多時候只是 JVM 已經爆了,但真正的根因可能是某個查詢撈太多資料、某個快取沒有釋放,或某個流程在短時間內開了太多執行緒。
如果環境是在 AIX,而且用的是 IBM 的 JVM,還會多一個落差:很多常見教學都在講 hprof 或 HotSpot 工具,但 AIX / IBM JVM 常見拿到的是 .phd dump。這時候就不能直接照一般教學走,要改用 IBM HeapAnalyzer 這類工具來看。
先講 OOM 排查不要只看 dump
Heap dump 很重要,但它只是拼圖的一塊。真正查 OOM,我會至少同時看這幾樣:
- 應用程式 log
- GC log
- thread dump / javacore
- heap dump
- 事故發生時間點附近的業務操作
原因很簡單:heap dump 告訴你「當下記憶體裡塞了什麼」,但不一定直接告訴你「為什麼塞了那麼多」。
AIX / IBM JVM 跟一般教學哪裡不一樣
在 Oracle HotSpot 或 OpenJDK 的文章裡,常會看到 .hprof。但在 AIX 上,如果是 IBM J9 / OpenJ9 相關環境,實務上常拿到的是 .phd 檔案與 javacore。
這也是我一開始卡住的地方:
- dump 有產生
- 但平常常見的分析工具不一定直接好用
- 搜尋一輪後才發現要改找 IBM HeapAnalyzer
工具連結:
基本排查流程
我自己的處理順序大概是下面這樣:
- 先從 log 確認 OOM 發生時間與錯誤型態。
- 確認當下有沒有產出
.phd、javacore或其他 dump。 - 用 IBM HeapAnalyzer 開
.phd。 - 看大物件、可疑類別、物件保留鏈。
- 再回頭對照 log 與業務流程,找出真正是哪段功能把 heap 撐爆。
IBM HeapAnalyzer 可以看什麼
打開 .phd 後,通常我會優先看幾件事:
- 哪些類別佔了最多記憶體。
- 哪些物件數量異常多。
- 某個大物件是被誰 reference 住。
- 是否存在明顯的集合類別暴增,例如
ArrayList、HashMap、快取容器等。
下面幾張圖是當時分析時的畫面紀錄。
看圖時我會怎麼判讀
HeapAnalyzer 能幫你很快看出「現在 heap 裡最肥的是誰」,但它不一定會直接跳出一句話告訴你「第幾行程式碼有問題」。所以判讀的關鍵還是在交叉比對。
例如你看到某個集合佔很大,就要繼續問:
- 這個集合屬於哪個模組?
- 它是暫存查詢結果,還是快取?
- 為什麼它沒有在預期時間內釋放?
- 是單筆物件太大,還是筆數太多?
很多時候,問題不是單一類別寫得很差,而是某段業務流程在錯的時間撈了太多資料。
這次實際查到的狀況
我這次碰到的情況,不是單純某個類別無限成長,而是程式本來會依 MQ 訊息開對應執行緒做處理。剛好同時間有兩支流程一起跑,其中一支會大量查資料,把 JVM heap 直接撐爆。
也就是說,真正的問題比較接近:
- 併行處理下,某個工作量太大。
- 單次查詢回來的資料量過多。
- 多條執行緒同時做重型工作,導致總記憶體快速升高。
最後的處理方式,不是單純加大 heap 就結束,而是先把那個重型排程移出去,避免它跟其他流程同時搶 JVM 記憶體。
我會特別再查的幾個方向
如果你也遇到類似問題,可以順手再確認:
- SQL 是否一次撈太多資料。
- 結果集有沒有全部先載入記憶體。
- 執行緒池大小是否合理。
- 快取是否設上限。
- 是否有大批次檔案、訊息或報表在同一時間集中處理。
因為很多 OOM 的根因其實不是「洩漏」,而是「設計上允許某段流程一次吃太多記憶體」。
心智圖
小結
在 AIX 上查 Java OOM,最大的差別是工具鏈要換一下思維,不是直接照一般 .hprof 教學走。IBM HeapAnalyzer 可以幫你找到 heap 裡哪些物件最可疑,但真正定位根因,還是要把 dump、 log、查詢行為與執行緒活動一起看。
這次我最後學到的重點是:不要太快把 OOM 當成單純的 JVM 參數問題,很多時候它反映的是業務流程和資料量的組合出了問題。
延伸參考: