windbg托管内存泄漏排查

news/2024/7/2 23:19:39

1、!address -summary  查看内存占用

        主要查看以下两项

        Heap:NT 堆 (同 !heap  -s),Size过大,可能有非托管内存泄露

        MEM_COMMIT:处于提交状态的内存大小,Size过大,可能有内存泄露

Heap              40        0`00d60000 (  13.375 MB)   0.20%    0.00%
MEM_COMMIT        742       0`8ea6e000 (   2.229 GB)  33.48%    0.00%

2、!eeheap -gc  查看托管堆占用

        托管堆已提交内存占用2Gb,和MEM_COMMIT大小大不多,可以确定是托管内存泄漏。

GC Committed Heap Size:    Size: 0x82a10000 (2191589376) bytes.

3、!dumpheap -stat 查看托管堆上对象分配情况

        String 类型的一般先不管,因为他一般都是被其他对象所持有的。这里主要看倒数第二项。

          MT      Count     TotalSize Class Name
7ffa04fe6618        571       136,952 System.Object[]
7ffa04feb1f0     16,215       389,160 System.Int32
7ffa056e66d0          2   134,217,776 Tedes.Model.Element[]
0000023d4f50 11,254,259   274,244,880 Free
7ffa056e60a8 13,100,201   524,008,040 Tedes.Model.Element
7ffa050a1e18 13,101,485 1,235,516,266 System.String

4、!dumpheap -mt 7ffa056e60a8  查看方法表对于的实例地址和占用内存大小。

        数据量太大这里会卡死一段时间,可以考虑出现一部分内容后截图,关掉windbg重开。

        随便找出一部分内容出来,放文档里

    Address               MT           Size
    0000aa9433d8     7ffa056e60a8             40 
    0000aa943478     7ffa056e60a8             40 
    0000aa943518     7ffa056e60a8             40 
    0000aa9435b8     7ffa056e60a8             40 
    0000aa943658     7ffa056e60a8             40 
    0000aa9436f8     7ffa056e60a8             40 
    0000aa943798     7ffa056e60a8             40 

5、!gcroot 0000aa9433d8   根据Address找到引用根

        随便找一个或多个Address来查看他的引用根,就知道是谁在溢出了

HandleTable:
    00000000023115f8 (pinned handle)
          --引用类型的静态变量会放在托管堆(小对象堆或大对象堆)中,被固定堆中的System.Object[]对象所持有
          -> 000012771038     System.Object[]             
          -> 00000290a180     System.Collections.Generic.List<Tedes.Model.Element> (static variable: Autofac.IContainer.container)            --真正泄露的集合
          -> 00006af01020     Tedes.Model.Element[] --对象实例数组,List内部就是数组
          -> 0000aa9433d8     Tedes.Model.Element   --对象实例

6、!dumpobj /d 00000290a180 查看一下这个对象实例

        看到_size 的大小有13100201个类实例。地址00000290a180就是找的溢出。可以在项目中查看哪里有定义Tedes.Model.Element[]的静态变量

        !objsize 00000290a180 可以查到占用了多少内存

0:000> !dumpobj /d 290a180
Name:        System.Collections.Generic.List`1[[Tedes.Model.Element, NFT.net]]
MethodTable: 00007ffa056e6138
EEClass:     00007ffa050ce048
Size:        32(0x20) bytes
File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.25\System.Private.CoreLib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffa05262ed8  4001c36        8     System.__Canon[]  0 instance 000000006af01020 _items
00007ffa04feb1f0  4001c37       10         System.Int32  1 instance         13100201 _size
00007ffa04feb1f0  4001c38       14         System.Int32  1 instance         13100201 _version
00007ffa05262ed8  4001c39        8     System.__Canon[]  0   static dynamic statics NYI                 s_emptyArray

7、如果还找不到哪里的问题(比如第三方dll有问题),可以找到具体的代码位置。

       7.1 找出谁引用了地址00000290a180,在System.Object[]的范围内搜索这个地址

                查看System.Object[]的大小: !do 000012771038

0:000> !do 000012771038     
Name:        System.Object[]
MethodTable: 00007ffa04fe6618
EEClass:     00007ffa04fe6580
Size:        8184(0x1ff8) bytes

                得出System.Object[]的地址范围为:000012771038 ~ 000012771038+0x1ff8

                查找命令为:s-q 000012771038 L?0x1ff8 00000290a180

                00000000`12772c58 就是想要的东西

0:000> s-q 000012771038 L?0x1ff8 00000290a180
00000000`12772c58  00000000`0290a180 00000000`028c75b8

        7.2 全内存搜索: s-b 0 L?0xffffffffffffffff 58 2c 77 12

                00000000`12772c58 需要将转为58 2c 77 12来搜索

                找到两个地址,如下:

0:000> s-b 0 L?0xffffffffffffffff 58 2c 77 12
00007ffa`05561811  58 2c 77 12 48 89 4d d8-48 8b 4d e0 e8 26 df ff  X,w.H.M.H.M..&..
00007ffa`0556193b  58 2c 77 12 48 8b 55 f8-e8 08 50 5f 5f 90 48 8d  X,w.H.U...P__.H.

        7.3 找到地址对应的方法:

!ip2md 00007ffa`05561811

在ButtonOkOnClick点击事件中有引用

0:000> !ip2md 00007ffa`05561811
MethodDesc:   00007ffa056b77c0
Method Name:          Tedes.View.AboutForm.ButtonOkOnClick(System.Object, System.EventArgs)
Class:                00007ffa0569f6b8
MethodTable:          00007ffa056b78b0
mdToken:              0000000006000005
Module:               00007ffa050bf7d0
IsJitted:             yes
Current CodeAddr:     00007ffa055617a0
Version History:
  ILCodeVersion:      0000000000000000
  ReJIT ID:           0
  IL Addr:            0000000000000000
     CodeAddr:           00007ffa055617a0  (MinOptJitted)
     NativeCodeVersion:  0000000000000000

!ip2md 00007ffa`0556193b 

在LayerService的静态构造函数中有引用,可能是静态变量的初始化操作。

0:000> !ip2md 00007ffa`0556193b
MethodDesc:   00007ffa051fad08
Method Name:          Tedes.Services.Layer.LayerService..cctor()
Class:                00007ffa05212070
MethodTable:          00007ffa051fad18
mdToken:              000000000600003A
Module:               00007ffa050bf7d0
IsJitted:             yes
Current CodeAddr:     00007ffa05561900
Version History:
  ILCodeVersion:      0000000000000000
  ReJIT ID:           0
  IL Addr:            0000000000000000
     CodeAddr:           00007ffa05561900  (MinOptJitted)
     NativeCodeVersion:  0000000000000000

        7.4 将对应模块dll导出:!savemodule 00007ffa050bf7d0 D:\ButtonOkOnClick.dll

                通过反编译工具查看就行


http://lihuaxi.xjx100.cn/news/2157327.html

相关文章

Swoole简单入门教程聊天系统

Swoole可以让PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP&#xff0c;WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。 一、使用Swoole实现在线聊天 建立服务端主程序 准…

利用Java实现每周二上午十点定时调用接口的方法

摘要&#xff1a; 在软件开发中&#xff0c;定时任务是一项常见的需求&#xff0c;特别是需要定期执行一些特定操作的场景。本文将介绍如何利用Java编程语言实现每周二上午十点定时调用接口的功能。通过使用Java中的定时任务调度工具&#xff0c;我们可以轻松地实现这一功能&am…

C++和C中的struct 和public有什么区别

在C和C语言中&#xff0c;struct 和 public 关键字分别具有不同的作用&#xff0c;它们的主要区别在于以下方面&#xff1a; struct&#xff08;结构体&#xff09;&#xff1a; 在C语言中&#xff0c;struct 用于定义自定义的复合数据类型&#xff0c;可以包含不同类型的成员变…

AI时代:程序员不是失业,而是逆袭的开始

&#x1f30c;引言&#xff1a; 在AI的浪潮之下&#xff0c;一个挑战性的问题逐渐浮出水面——AI的崛起是否意味着程序员的失业&#xff1f;这个问题不仅激发了技术界的广泛讨论&#xff0c;也触动了每一位程序员的心弦。然而&#xff0c;在这背后&#xff0c;我们应该看到的是…

简单使用Linux printf 将十进制转换为十六进制

在开发和排查问题过程中&#xff0c;有时我们需要做一些进制的转换&#xff0c;以下是一些快速的小技巧&#xff1a; 下面的是 十进制转换为十六进制&#xff1a; ❯ printf "0x%x\n" 100 0x64 还可以把 十六进制转为十进制&#xff1a; ❯ printf "%d\n&q…

SpringMVC转发和重定向

转发和重定向 1. View Resolver Spring MVC 中的视图解析器&#xff08;View Resolver&#xff09;负责解析视图。可以通过在配置文件中定义一个 View Resolver 来配置视图解析器&#xff1a; 配置文件版&#xff1a;spring-web.xml <!-- for jsp --> <bean class&q…

MySQL View 视图

拓展阅读 MySQL View MySQL truncate table 与 delete 清空表的区别和坑 MySQL Ruler mysql 日常开发规范 MySQL datetime timestamp 以及如何自动更新&#xff0c;如何实现范围查询 MySQL 06 mysql 如何实现类似 oracle 的 merge into MySQL 05 MySQL入门教程&#xff0…

Javascript - 你在项目中是如何使用闭包的

难度级别:中高级及以上 提问概率:80% 很多初级开发者其实在日常工作中,很少有使用闭包的机会,但这却是一个非常高频的考点,因为对闭包不是特别了解,使用又少,久而久之,就觉得闭包是一个难点。在Javascript中,一个普通方法在执行完毕后…