日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序怎么跑着 就卡死,句柄泄漏,内存泄漏了

發布時間:2023/12/4 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序怎么跑着 就卡死,句柄泄漏,内存泄漏了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:背景

1. 講故事

上個月中旬,星球里的一位朋友在微信找我,說他的程序跑著跑著內存會不斷的緩慢增長并無法釋放,尋求如何解決 ?

得,看樣子星球還得好好弄!!!😂😂😂 ?不管怎么說,先上 windbg 說話。

二:Windbg 分析

1. 經驗推理

從朋友的截圖看,有大量的 8216 字節的 byte[],這表示什么呢?追隨本系列的朋友應該知道,有一篇 某三甲醫院 的內存暴漲的dump中,也同樣有此 size= (8216-24=8192) 的 byte[] 數組, 他的問題是 Oracle 中讀取某大字段時sdk里的 OraBuf 出了問題,換句話說,這肯定又是底層或者第三方庫中的池對象搞出來的東西,接下來從 托管堆 看起。

2. 查看托管堆

0:000>?!dumpheap?-stat Statistics: 00007ffe107248f0???483707?????15478624?System.Threading.PreAllocatedOverlapped 00007ffe1079c160???483744?????15479808?System.Threading.ThreadPoolBoundHandle 00007ffe1079cff8???483701?????23217648?System.Threading._IOCompletionCallback 00007ffe106e7a90???483704?????23217792?Microsoft.Win32.SafeHandles.SafeFileHandle 00007ffe1079b088???483703?????30956992?System.IO.FileSystemWatcher+AsyncReadState 00007ffe1079ceb0???483707?????34826904?System.Threading.OverlappedData 00007ffe1079ccb0???483707?????34826904?System.Threading.ThreadPoolBoundHandleOverlapped 0000016c64651080???245652???1473128080??????Free 00007ffe105abf30???488172???3977571092?System.Byte[]

掃完托管堆,臥槽 ,byte[] 沒吸引到我,反而被 System.IO.FileSystemWatcher+AsyncReadState 吸引到了,畢竟被 System.IO.FileSystemWatcher 折騰多次了,它已經深深打入了我的腦海。。。畢竟讓程序卡死,讓句柄爆高的都是它。。。這一回八成又是它惹的禍,看樣子還是有很多程序員栽在這里哈。

為做到嚴謹,我還是從最大的 System.Byte[] 入手,按size對它進行分組再按totalsize降序,丑陋的腳本我就不發了,直接上腳本的輸出結果。

!dumpheap?-mt?00007ffe105abf30 size=8216,count=483703,totalsize=3790M size=8232,count=302,totalsize=2M size=65560,count=6,totalsize=0M size=131096,count=2,totalsize=0M size=4120,count=11,totalsize=0M size=56,count=301,totalsize=0M size=88,count=186,totalsize=0M size=848,count=16,totalsize=0M size=152,count=85,totalsize=0M size=46,count=242,totalsize=0M size=279,count=38,totalsize=0M!dumpheap?-mt?00007ffe105abf30?-min?0n8216?-max?0n8216?-short0000016c664277f0 0000016c66432a48 0000016c6648ef88 0000016c6649daa8 0000016c6649fb00 0000016c664a8b90 ...

從輸出結果看,size=8216 的 byte[] 有 48w 個,然后腳本也列出了一些 8216 大小的 address 地址,接下來用 !gcroot 看下這些地址的引用。

0:000>?!gcroot?0000016c664277f0 HandleTable:0000016C65FC28C0?(async?pinned?handle)->?0000016C6628DEB0?System.Threading.OverlappedData->?0000016C664277F0?System.Byte[]Found?1?unique?roots?(run?'!gcroot?-all'?to?see?all?roots). 0:000>?!gcroot?0000016c667c80d0 HandleTable:0000016C65FB7920?(async?pinned?handle)->?0000016C663260F8?System.Threading.OverlappedData->?0000016C667C80D0?System.Byte[]

從輸出中可以看到這些 byte[] 都是 async pinned,也就是當異步IO回來的時候需要給 byte[] 填充的存儲空間,接下來我們看看如何通過 OverlappedData 找到源碼中定義為 8192 大小的 byte[] 地方。

如果你了解 FileSystemWatcher ,反向查找鏈大概是這樣的 OverlappedData -> ThreadPoolBoundHandleOverlapped -> System.IO.FileSystemWatcher+AsyncReadState -> Buffer[], 這中間涉及到 ThreadPool 和 SafeHandle 的綁定。

0:000>?!do?0000016C663260F8 Name:????????System.Threading.OverlappedData MethodTable:?00007ffe1079ceb0 EEClass:?????00007ffe107ac8d0 Size:????????72(0x48)?bytes File:????????C:\Program?Files\dotnet\shared\Microsoft.NETCore.App\5.0.10\System.Private.CoreLib.dll Fields:MT????Field???Offset?????????????????Type?VT?????Attr????????????Value?Name 00007ffe106e3c08??40009ce????????8??System.IAsyncResult??0?instance?0000000000000000?_asyncResult 00007ffe104a0c68??40009cf???????10????????System.Object??0?instance?0000016c66326140?_callback 00007ffe1079cb60??40009d0???????18?...eading.Overlapped??0?instance?0000016c663260b0?_overlapped 00007ffe104a0c68??40009d1???????20????????System.Object??0?instance?0000016c667c80d0?_userObject 00007ffe104af508??40009d2???????28??????????????????PTR??0?instance?00000171728f66e0?_pNativeOverlapped 00007ffe104aee60??40009d3???????30????????System.IntPtr??1?instance?0000000000000000?_eventHandle 00007ffe104ab258??40009d4???????38?????????System.Int32??1?instance????????????????0?_offsetLow 00007ffe104ab258??40009d5???????3c?????????System.Int32??1?instance????????????????0?_offsetHigh 0:000>?!do?0000016c663260b0 Name:????????System.Threading.ThreadPoolBoundHandleOverlapped MethodTable:?00007ffe1079ccb0 EEClass:?????00007ffe107ac858 Size:????????72(0x48)?bytes File:????????C:\Program?Files\dotnet\shared\Microsoft.NETCore.App\5.0.10\System.Private.CoreLib.dll Fields:MT????Field???Offset?????????????????Type?VT?????Attr????????????Value?Name 00007ffe1079ceb0??40009d6????????8?...ng.OverlappedData??0?instance?0000016c663260f8?_overlappedData 00007ffe1079b818??40009c0???????10?...ompletionCallback??0?instance?0000016f661ab8a0?_userCallback 00007ffe104a0c68??40009c1???????18????????System.Object??0?instance?0000016c667ca0e8?_userState 00007ffe107248f0??40009c2???????20?...locatedOverlapped??0?instance?0000016c66326090?_preAllocated 00007ffe104af508??40009c3???????30??????????????????PTR??0?instance?00000171728f66e0?_nativeOverlapped 00007ffe1079c160??40009c4???????28?...adPoolBoundHandle??0?instance?0000000000000000?_boundHandle 00007ffe104a7238??40009c5???????38???????System.Boolean??1?instance????????????????0?_completed 00007ffe1079b818??40009bf??????738?...ompletionCallback??0???static?0000016f661ab990?s_completionCallback 0:000>?!do?0000016c667ca0e8 Name:????????System.IO.FileSystemWatcher+AsyncReadState MethodTable:?00007ffe1079b088 EEClass:?????00007ffe107a9dc0 Size:????????64(0x40)?bytes File:????????C:\Program?Files\dotnet\shared\Microsoft.NETCore.App\5.0.10\System.IO.FileSystem.Watcher.dll Fields:MT????Field???Offset?????????????????Type?VT?????Attr????????????Value?Name 00007ffe104ab258??400002b???????30?????????System.Int32??1?instance????????????????1?<Session>k__BackingField 00007ffe105abf30??400002c????????8????????System.Byte[]??0?instance?0000016c667c80d0?<Buffer>k__BackingField 00007ffe106e7a90??400002d???????10?...es.SafeFileHandle??0?instance?0000016c66326028?<DirectoryHandle>k__BackingField 00007ffe1079c160??400002e???????18?...adPoolBoundHandle??0?instance?0000016c66326058?<ThreadPoolBinding>k__BackingField 00007ffe107248f0??400002f???????20?...locatedOverlapped??0?instance?0000016c66326090?<PreAllocatedOverlapped>k__BackingField 00007ffe1079b8c8??4000030???????28?...eSystem.Watcher]]??0?instance?0000016c66326078?<WeakWatcher>k__BackingField

上面的 <Buffer>k__BackingField 就是當初丟給 OverlappedData 作為 異步IO 讀寫的緩沖,然后看下 System.IO.FileSystemWatcher+AsyncReadState 的源碼。

有了這些原理之后,接下來就可以問朋友是否有對 appsettings 設置了 reloadonchange=true 的情況,朋友找了下代碼,寫法大概如下:

public?object?GetxxxFlag() {string?value?=?AppConfig.GetConfig("appsettings.json").GetValue("xxxx",?"0");return?new{state?=?200,data?=?value}; }public?class?AppConfig {public?static?AppConfig?GetConfig(string?settingfile?=?"appsettings.json"){return?new?AppConfig(settingfile);} }public?class?AppConfig {private?AppConfig(string?settingfile){_config?=?new?ConfigurationBuilder().AddJsonFile(settingfile,?optional:?true,?reloadOnChange:?true).Build();_settingfile?=?settingfile;} }

從源碼邏輯看,我猜測朋友將 ?GetConfig 方法標記成 static 后就以為是單例化了,再次調用不會重復 new AppConfig(settingfile),所以問題就出在這里。

不過有意思的是,前面二篇的 FileSystemWatcher 都會造成程序卡死,那這一篇為啥沒有呢?恰好他沒有在程序根目錄中放日志文件,不然的話。。。😄😄😄,可萬萬沒想到逃過了卡死卻沒逃過一個 watcher 默認 8byte 空間的靈魂拷問。。。😂😂😂

三:總結

總的來說,設置 reloadOnChange: true 一定要慎重, 可能它會造成你的程序卡死,句柄泄漏,內存泄漏 等等!!!改進方案我就不說了,參考我前面的系列文章吧。

END

工作中的你,是否已遇到 ...?

1. CPU爆高

2. 內存暴漲

3. 資源泄漏

4. 崩潰死鎖

5. 程序呆滯

等緊急事件,全公司都指望著你能解決...? 危難時刻才能展現你的技術價值,作為專注于.NET高級調試的技術博主,歡迎微信搜索: 一線碼農聊技術,免費協助你分析Dump文件,希望我能將你的踩坑經驗分享給更多的人。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的程序怎么跑着 就卡死,句柄泄漏,内存泄漏了的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。