Docker部署.netCore6 第一步:在項目添加Docker支持 第二步:選擇Windows(如果是linx系統就選擇linx)和Dockerfile 第三步:生成Docker預設文件 把預設代碼修改 第四步:修改Dockerfile文件屬性(如果不修改則會導致發佈的時候Docker文件沒有一 ...
作者就職的公司在19年就開始使用.net core並且部署到Linux上,這些年也遇到不少問題,有些問題都是使用土方法去解決,後面再慢慢寫吧,準備將遇到的問題寫成一個系列。
前情提要
本次的項目是20年上線的儲值卡系統,上線後發現記憶體緩慢增長(半個月漲到4G多),一直沒有找到原因就讓運維小伙伴設置每半個月重啟來解決這個問題,但是公司的發展增長的記憶體越來越大,不得不去學習一些知識去解決這個問題了。這就有了今天這篇博文。
讓運維小伙伴幫忙拿到dump,開始分析。(如何從Linux拿到dump?參考黃老師(一線碼農)的博文:Linux 上的 .NET 崩潰了怎麼抓 Dump - 一線碼農 - 博客園 (cnblogs.com))
分析思路:
一、先觀察一下dump的摘要信息
打開WinDbg,使用 !address -summary
命令觀察摘要信息
發現 MEM_COMMIT 中占用1.501GB
二、判斷是托管記憶體還是非托管記憶體泄露
1、使用 !eeheap -gc
命令觀察一下
發現 Small object heap(小對象堆)占了800多M的記憶體,Large object heap(大對象堆)占了90多M的記憶體,那還有500多M的記憶體在哪裡呢?
2、那我們通過!sos maddress -summary
命令觀察一下
發現棧(stack)和映像(Image)占了519M記憶體,上面缺少的500多M在這裡了,這個占用是正常的,那麼我們就可以確認問題出現在Small object heap(小對象堆)中了
三、看看統計下托管堆上記憶體所有對象和小對象堆中的記憶體所有對象
1、通過 !sos dumpheap -stat
命令查看托管堆上記憶體所有對象
發現數量最多分別是Dapper.SqlMapper+CacheInfo和Dapper.SqlMapper+Identity和string,我們在來看看某個小對象堆中的所有對象是不是這些內容
2、通過 !dumpheap -segment
XXX(小對象堆中的segment) 命令觀察小對象堆上記憶體所有對象
發現和上面托管堆的中的對象一樣,那我們接下來就去看看數量最多string中都是些什麼東西吧。
四、查看string對象中的內容
1、通過 !dumpheap -mt
7f6f8b160f90 命令查看對象中的信息
內容有點多,那我們就看看其中一個對象的內容吧
2、通過 !dumpobj /d
7f6f73ffadd8 命令查看對象中的內容
????怎麼會是sql語句呢?我再多看幾個
怎麼都是sql呀?????那我就看看誰在占用它吧
3、通過 !sos gcroot
7f6f71cf4ac8 命令查看誰在占用該記憶體對象
居然是dapper在占用它,看上去是dapper的緩存?啊???dapper還把sql語句都作為緩存了?
好我們找到問題了,那就開始解決它
解決問題:
一、要解決問題那必須先瞭解問題
通過查看源碼,找到Dapper.SqlMapper.Identity
發現會緩存起來,為什麼會緩存起來呢?原因是為了效率
(詳細的大家請看:深入Dapper.NET源碼 (文長) - 阿翰 - 博客園 (cnblogs.com))
二、解決辦法
1、規範sql,條件都必須通過參數傳遞,避免緩存過得造成記憶體泄露
2、如果沒辦法規範sql怎麼辦呢?也有解決版本
通過閱讀源碼發現有兩個方法 SqlMapper.GetCachedSQLCount()
和SqlMapper.PurgeQueryCache()
,可以通過以上兩個方法解決這個問題,避免過多的緩存,如果大於閾值就清空緩存
下一篇再見了大家