我正在寻找.NET项目中的内存和资源泄漏,因为应用程序最终会崩溃,出现一些普通的GDI+异常,有时还会出现OOM错误。我正在分析的库使用了System.Graphics API,但没有直接指向GUI。我正在使用VisualStudio2019企业版和内置性能分析器工具来分析内存使用情况。该工具是用来捕获托管和本机堆使用情况的。我拍了两张照片。第一个是库尚未被调用时的基线。第二个快照是在循环中重复调用库方法并最终调用GC.Collect()和GC.WaitForPendingFinalizers()之后。下面是内存使用图的截图。第一个显示托管堆,第二个显示本机堆。
事件探查器显示托管堆的输出

Profiler输出显示本机堆

进程资源管理器在据称泄漏后的条目

分析WinDbg中的内存转储
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 891 7ffd`bb247000 ( 127.991 TB) 99.99%
<unknown> 916 2`3b96d000 ( 8.931 GB) 98.40% 0.01%
Image 471 0`0837e000 ( 131.492 MB) 1.41% 0.00%
Heap 35 0`007e4000 ( 7.891 MB) 0.08% 0.00%
Stack 21 0`00700000 ( 7.000 MB) 0.08% 0.00%
Other 8 0`001cb000 ( 1.793 MB) 0.02% 0.00%
TEB 7 0`0000e000 ( 56.000 kB) 0.00% 0.00%
PEB 1 0`00001000 ( 4.000 kB) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 944 2`395e9000 ( 8.896 GB) 98.02% 0.01%
MEM_IMAGE 491 0`08a1a000 ( 138.102 MB) 1.49% 0.00%
MEM_MAPPED 24 0`02da6000 ( 45.648 MB) 0.49% 0.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 891 7ffd`bb247000 ( 127.991 TB) 99.99%
MEM_COMMIT 1379 1`287f4000 ( 4.633 GB) 51.05% 0.00%
MEM_RESERVE 80 1`1c5b5000 ( 4.443 GB) 48.95% 0.00%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 1010 1`1e71f000 ( 4.476 GB) 49.31% 0.00%
PAGE_EXECUTE_READ 52 0`05ec3000 ( 94.762 MB) 1.02% 0.00%
PAGE_READONLY 180 0`032ca000 ( 50.789 MB) 0.55% 0.00%
PAGE_WRITECOPY 113 0`00ed6000 ( 14.836 MB) 0.16% 0.00%
PAGE_EXECUTE_READWRITE 17 0`00051000 ( 324.000 kB) 0.00% 0.00%
PAGE_READWRITE|PAGE_GUARD 7 0`00021000 ( 132.000 kB) 0.00% 0.00%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 1`3dbe9000 7ff2`c85d7000 ( 127.948 TB)
<unknown> 7ff4`06370000 1`00020000 ( 4.000 GB)
Image 7ffd`63eba000 0`0103d000 ( 16.238 MB)
Heap 0`1ded2000 0`0017d000 ( 1.488 MB)
Stack 0`1bac0000 0`000fa000 (1000.000 kB)
Other 0`017d0000 0`00181000 ( 1.504 MB)
TEB 0`00e0d000 0`00002000 ( 8.000 kB)
PEB 0`00e0c000 0`00001000 ( 4.000 kB)令我费解的是,图中的内存使用量(私有字节)一直在增长(高达5GB),但是快照#2只显示了大约2.55MB的本地堆和大约316 KB的托管堆使用情况。实际上,这个库函数被调用了大约400次,只是为了加剧这个问题。私有字节的使用与循环计数成正比。尽管每次迭代之后,库方法返回的对象都会被释放,但是内存使用永远不会达到稳定状态,并且如果循环计数增加,则会不断增加。这一点以及最终的GDI+异常对我来说意味着库正在泄漏句柄或内存,但分析器输出似乎没有表明这一点。如果有人能对这件事有所了解并帮助我理解我在这里看到的,我会很高兴的。
发布于 2020-05-14 15:13:08
正如@ThomasWeller所指出的,这最终是图像数据的泄露。我想我会在这里发表我的发现作为答案,希望它能对某人有所帮助。
在与WinDbg度过了一段时间之后,我仍然找不到任何帮助我解决这个漏洞的东西,这可能是因为我在使用这个工具方面缺乏专业知识。然后,我遇到了一个使用来自SysInternals的SysInternals实用工具的建议。我发现这很容易使用,但显然没有WinDbg那么强大。下面显示的是泄漏发生后VMMap的屏幕截图。

可以看到,堆的使用率仅为8MB,而私有数据的使用率约为9GB。单击“私有数据条目”显示数百个相同大小的分配条目。鉴于图书馆的性质,这表明它是某种图像数据。我的第一个怀疑是位图对象没有被处理,但是查看代码中位图的每一次使用都没有发现任何东西。然而,在看这个时,我发现了一个对Bitmap.LockBits的调用,它没有相应的UnlockBits调用。事实证明这是泄漏的原因。
https://stackoverflow.com/questions/61737804
复制相似问题