1. 程式人生 > >記一次記憶體飆升的Windbg

記一次記憶體飆升的Windbg

# 背景 突然間接到運維的報警,我們一個服務,記憶體找過了6GB的佔用。才6GB 也不是很大,因為在處理別的事情,服務dump一下暫時一放,然後半小時之後,接到了運維的Kafka堆積報警。然後切換著重啟了一下兩個節點,Kafka消費速率回覆正常,記憶體也從500M攀升到2GB後逐漸穩定。當天半夜,運維又報警,不過已經熟睡的我,並沒有第一時間響應,第二天觀察了一下服務,發現記憶體已經迴歸到了2GB左右。 ## 記憶體飆升 與 Kafka堆積是否是一件事情 拉出表格來對比一下時間發現,這兩個事情,時間節點基本上是能對的上的,所以大概率是一件事情。 ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a136f34a36c649409aa192af5737accf~tplv-k3u1fbpfcp-zoom-1.image) ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b65147b2c0e6465ab05cc1a338acdbb6~tplv-k3u1fbpfcp-zoom-1.image) ## dump分析 這麼看來只要解了記憶體飆升的問題,Kafka堆積的問題應該也就會一併解決。那麼,我們來分析一下,為什麼會出現記憶體飆升吧。 首先看一下記憶體的整體使用情況 `!dumpheap -stat` ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/beccd1934a7a42af8cbaf81979698ee2~tplv-k3u1fbpfcp-zoom-1.image) 發現跟字串關係很大,下邊的Free應該是記憶體釋放了,但是GC還沒有及時回收的記憶體。 字串1GB + 未回收記憶體3GB + 其他 林林總總 約等於 6G,差不多。下面我們重點追查一下這個字串是怎麼回事。 `!DumpHeap -mt 000007fef956aee0 -min 200` ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3dea1dcb47704f5688d511e0ed065e64~tplv-k3u1fbpfcp-zoom-1.image) 出現了大量的 500Byte左右大小的字串。這個大小,感覺像是業務字串,並且應該是不重複的。先隨便搞一條出來看看。 `!do 000000008966ee78` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10a09bf2138949128f36d8c46df77afa~tplv-k3u1fbpfcp-zoom-1.image) 這個內容有點莫名的眼熟,這不是我們傳送訊息給釘釘,然後再查詢一下,釘釘的訊息傳送結果的返回值嘛?大概已經知道,是哪段邏輯出的錯了,程式碼雖然不是我寫的,但是我大概知道有這麼一段邏輯。可是這段為什麼會讓記憶體暴增呢?查一下引用堆疊。 `!GCRoot 000000008966ee78` ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dff0be4d993b4510a08966a6a6f07fd5~tplv-k3u1fbpfcp-zoom-1.image) 發現上層的引用是一個List,我們列印一下這個List看看。 `!DumpObj 0000000313b371a0` ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/15b04a5febd84a14a9c85f3ac34fc6c6~tplv-k3u1fbpfcp-zoom-1.image) 發現這個List好像是不小,12000+。粗略算算 12000 * 500 / GB 大概 5.xGB,但是現在記憶體只用了1GB多點,分析一下原始碼。 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c2573b8fcb4d4edfa9e14b1d022adb65~tplv-k3u1fbpfcp-zoom-1.image) 那個List 應該就是對應了這個tasks物件了。 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bc8cebf290794937b4b1398b740e932c~tplv-k3u1fbpfcp-zoom-1.image) ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c006d6d1c5754bd2a07a04f3a85c286a~tplv-k3u1fbpfcp-zoom-1.image) 後邊會把查詢的資料,序列化,然後放到這個物件上,在插入到資料庫中。 簡單總結一下原因,是因為一次性取出來的物件有點多(12000)條,然後挨個查詢他的訊息的傳送結果,然後將網路呼叫的查詢結果,序列化到物件上,然後再儲存到資料庫中。因為這些Model都被引用在一個List中,所以當12000個數據全都被處理完成之後才會釋放List的記憶體。這樣,每次處理,記憶體都跟坐過山車一樣。 問題定位到了,解決方式就很簡單了,隨便搞。 啊,又解決一個問題,我變強了。 我的掘金 https://juejin.im/post/686846696437