💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
1.用windbg或者VS加载SOS.dll, 可以参考我的另外一篇“如何用Visual Studio集成SOS.dll进行调试” 2.  (1)用GCHandleLeaks调查    具体示例如下: 0:003> **!gchandleleaks** ------------------------------------------------------------------------------- GCHandleLeaks will report any GCHandles that couldn't be found in memory.      Strong and Pinned GCHandles are reported at this time. You can safely abort the memory scan with Control-C or Control-Break.                                   ------------------------------------------------------------------------------- Found 249 handles: 0000000001dc1200     0000000001dc1208     0000000001dc1210    0000000001dc1218     0000000001dc1220     0000000001dc1228     0000000001dc1230    0000000001dc1238     0000000001dc1240     0000000001dc1248     0000000001dc1250    0000000001dc1258     0000000001dc1260     0000000001dc1268     0000000001dc1270    0000000001dc1278     0000000001dc1280     0000000001dc1288     0000000001dc1290    0000000001dc1298     0000000001dc12a0     0000000001dc12a8     0000000001dc12b0    0000000001dc12b8     …*(the list goes on)* Searching memory Found 0000000001dc1ff8 at location 000000000012ce48 Found 0000000001dc1380 at location 0000000000145870 Found 0000000001dc1390 at location 0000000000145918 Found 0000000001dc1378 at location 00000000001557f8 … ------------------------------------------------------------------------------ Some handles were not found. If the number of not-found handles grows over the lifetime of your application, you may have a GCHandle leak. This will cause   the GC Heap to grow larger as objects are being kept alive, referenced only   by the orphaned handle. If the number doesn't grow over time, note that there may be some noise in this output, as an unmanaged application may be storing  the handle in a non-standard way, perhaps with some bits flipped. The memory  scan wouldn't be able to find those.                                          ------------------------------------------------------------------------------ Didn't find 232 handles: 0000000001dc1200     0000000001dc1208     0000000001dc1210    0000000001dc1218     0000000001dc1220     0000000001dc1228     0000000001dc1230    0000000001dc1238     0000000001dc1240     0000000001dc1248     0000000001dc1250    0000000001dc1258     0000000001dc1260     0000000001dc1268     0000000001dc1270    0000000001dc1278     0000000001dc1280     0000000001dc1288     0000000001dc1290    0000000001dc1298     ... "Didn't find XXX handles"就是我们需要关注的有可能泄露的句柄, 我们选一个进行查看, 如下: 0:003> **!dumpobj poi(**0000000001dc1280) Name: BloatedObject MethodTable: 00000642801315c0 EEClass: 0000064280163cd0 Size: 32(0x20) bytes (C:\pub\eetwc\windowh.exe) Fields:              MT    Field   Offset                 Type VT    Attr            Value Name 000006423756d248  4000001        8 System.IO.TextWriter  0 instance 0000000010353c28 tw 00000642375dba38  4000002       10        System.Byte[]  0 instance 0000000022e50080 **ba** (2)利用dumpheap -stat和dumpobj 首先用dumpheap -stat列出所有类型的堆信息, 如下: 0:000> !dumpheap -stat 0x79c489a0          1            12 System.Runtime.Remoting.Messaging.ClientContextTerminatorSink 0x79bf9aec          1            12 System.IO.TextReader/NullTextReader 0x79be7078          1            12 System.Runtime.Remoting.Proxies.ProxyAttribute 0x79bce8e0          1            12 System.Runtime.InteropServices.ComVisibleAttribute 0x79bce7c8          1            12 System.CLSCompliantAttribute 0x79bc08e0          1            12 System.Empty 0x0618ae68          1            12 System.Web.Configuration.CustomErrorsConfigHandler 0x061887f8          1            12 System.Web.UI.WebControls.UnitConverter 0x06180848          1            12 System.Drawing.ColorConverter 0x05dbfbc4          1            12 System.Data.Res 第一列是地址,第二列是数量, 第三列是总共大小,第四列是具体类型名字, 需要注意的是第三列总共大小不包含成员变量的大小。 在其中找到异常的类型的堆地址, 比如有些类型的数量太大。 而后利用dumpobj来查看, 如下: 0:000> !dumpobj 0x05dbfbc4 Name: System.Data.DataSet MethodTable 0x060bbd2c EEClass 0x060d2614 Size 80(0x50) bytes GC Generation: 2 mdToken: 0x0200003b  (c:\windows\assembly\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll) FieldDesc*: 0x060bb358        MT      Field     Offset                 Type       Attr      Value Name 0x060b252c 0x4000583      0x4                CLASS   instance 0x00000000 site 0x060b252c 0x4000584      0x8                CLASS   instance 0x00000000 events 0x060b252c 0x4000582        0                CLASS     shared   static EventDisposed    >> Domain:Value 0x001192a0:NotInit  0x0017fc40:NotInit  0x044b7b28:0x1c357cb8 << 0x060bbd2c 0x40003d3      0xc                CLASS   instance 0x00000000 defaultViewManager 0x060bbd2c 0x40003d4     0x10                CLASS   instance 0x3920ee28 tableCollection 0x060bbd2c 0x40003d5     0x14                CLASS   instance 0x3920ed9c relationCollection 0x060bbd2c 0x40003d6     0x18                CLASS   instance 0x00000000 extendedProperties 0x060bbd2c 0x40003d7     0x1c                CLASS   instance 0x1c357c90 dataSetName 0x060bbd2c 0x40003d8     0x20                CLASS   instance 0x182d0224 _datasetPrefix 0x060bbd2c 0x40003d9     0x24                CLASS   instance 0x182d0224 namespaceURI 0x060bbd2c 0x40003da     0x40       System.Boolean   instance 0 caseSensitive 0x060bbd2c 0x40003db     0x28                CLASS   instance 0x14309a0c culture 0x060bbd2c 0x40003dc     0x41       System.Boolean   instance 1 enforceConstraints 0x060bbd2c 0x40003dd     0x42       System.Boolean   instance 0 fInReadXml 0x060bbd2c 0x40003de     0x43       System.Boolean   instance 0 fInLoadDiffgram 0x060bbd2c 0x40003df     0x44       System.Boolean   instance 0 fTopLevelTable 0x060bbd2c 0x40003e0     0x45       System.Boolean   instance 0 fInitInProgress 0x060bbd2c 0x40003e1     0x46       System.Boolean   instance 1 fEnableCascading 0x060bbd2c 0x40003e2     0x47       System.Boolean   instance 0 fIsSchemaLoading 0x060bbd2c 0x40003e3     0x2c                CLASS   instance 0x00000000 rowDiffId 0x060bbd2c 0x40003e4     0x48       System.Boolean   instance 0 fBoundToDocument 0x060bbd2c 0x40003e5     0x30                CLASS   instance 0x00000000 onPropertyChangingDelegate 0x060bbd2c 0x40003e6     0x34                CLASS   instance 0x00000000 onMergeFailed 0x060bbd2c 0x40003e7     0x38                CLASS   instance 0x00000000 onDataRowCreated 0x060bbd2c 0x40003e8     0x3c                CLASS   instance 0x00000000 onClearFunctionCalled 0x060bbd2c 0x40003e9        0                CLASS     shared   static zeroTables    >> Domain:Value 0x0017fc40:NotInit  0x044b7b28:0x1c357c80 << 如果想要查看对象的实际大小值,即也包含成员变量的大小。 请用!objsize 内存地址 我们也可以指定查看具体类型的堆地址, 请用!dumpheap -type 类型名 (3)使用clrstack和finalizeQueue 我们用clrstack查看当前gc中对象情况, 然后用finalizeQueue查看即将要被回收的对象情况, 两者对比下,数量不对或者没被回收的都有可能是内存泄露。 最后, 调查内存泄露是个费时费力还不一定有结果的事情, 祝愿大家都能找出具体问题。