最近,我看到在 grafana 監控畫面中,負責乙個服務的兩個節點的老一代內存在穩步上公升,並且沒有觸發主 GC。
然後我聯絡了我的運維同事幫忙匯出轉儲檔案,並選擇了 pod 1 來執行 jmap -dump:live,format=b,file=heap001 命令
Pod 1 執行 dump 命令後,舊代記憶體趨勢如下圖所示
正如你所看到的,這個 dump 觸發了一次 major GC(heap dump initiated),並且舊 gen 記憶體很快就被釋放了,因此可以推斷出在這個服務例項之前的舊時代存在大量垃圾物件,因為沒有觸發 major GC,導致這些物件一直占用記憶體,沒有及時清除。
那麼,有哪些物品一直在源源不斷地進入老年呢?
Pod 2 和 Pod 1 的資源配置是一樣的,老一代記憶體的趨勢也差不多,然後讓運維同事在 pod 2 上執行 dump 命令:jmap -dump:format=b,file=heap002,除了生成的檔名和 Pod 1 不同之外,應該已經發現這個命令缺少乙個可選引數 live, 因此,在生成記憶體快照之前不會觸發完整的 GC。觀察垃圾物件的情況對我們大有裨益。
使用 IDEA 中的外掛程式分析器來分析堆轉儲檔案。
觀察 class 標籤頁,按照淺層從大到小排序(shalllow 表示該物件占用的堆的大小,retained 表示堆中物件在下乙個 major gc 之後的大小)。 與業務直接相關的兩個類** applicationbank 和 regiontree 可以清楚地看到,在這兩個類的例項中,有近 140m 的垃圾物件沒有被使用。 然後就可以準確地找到相關類,從而找到關鍵業務**:
regiontree 也有相應的快取。 看到這裡,結論就一定很清楚了:每30分鐘重新整理一次localcache快取,這些快取例項也算是長期生存物件,要麼因為年齡(預設為15歲)而達到入職年齡,要麼因為動態年齡決定機制,或者因為空間分配保證機制進入老年也是正常的。
至此,老一代記憶體崛起緩慢的原因已經揭曉,JVM記憶體中有一些長期存活的快取物件,這些快取物件每隔一段時間就會用新例項重新生成。
那麼這對應用程式有什麼影響嗎? 從應用目前的狀態來看,即使記憶體增長緩慢,也沒有觸發 major gc,這意味著這些快取物件的集合量並不大,即使過了很長一段時間,達到了舊世代記憶體的限制,那麼 major gc 就會發生清理這些垃圾, 這也是正常的。目前,此應用程式發生的主要 GC 數量非常少。 所以這個應用的記憶體情況是正常的。
要確定乙個應用的記憶體,我們可以從應用使用的HEAP記憶體量、GC是否可以釋放HEAP記憶體、GC的頻率、耗時等入手。當你發現記憶體問題時,可以使用jmap命令獲取JVM記憶體的快照,並使用一些轉儲分析工具(profiler、yourkit(paid))進行深入的記憶體分析,找出問題所在。
2月** 動態激勵計畫