惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
S
Security @ Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
The Hacker News
The Hacker News
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
博客园 - 司徒正美
雷峰网
雷峰网
L
LINUX DO - 最新话题
博客园 - 叶小钗
云风的 BLOG
云风的 BLOG
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术
S
Security Affairs
有赞技术团队
有赞技术团队
月光博客
月光博客
T
Threatpost
T
Tor Project blog
O
OpenAI News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
Know Your Adversary
Know Your Adversary
Project Zero
Project Zero
博客园 - 三生石上(FineUI控件)
D
Docker
AWS News Blog
AWS News Blog
AI
AI
P
Proofpoint News Feed
K
Kaspersky official blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Securelist
F
Fortinet All Blogs
F
Full Disclosure
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Palo Alto Networks Blog
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
美团技术团队
N
News | PayPal Newsroom
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog

博客园 - 一线码农

.NET 生产环境调试实战指南 记一次 .NET 某光电成像后端解析系统 内存暴涨分析 记一次 .NET 某注塑模具系统 CPU爆高分析 记一次 .NET 某集群管理软件 内存暴涨分析 记一次 .NET 某智慧工厂视觉程序 崩溃分析 记一次 .NET 某低代码开发框架 内存暴涨分析 记一次 .NET 某MES上位机拍照系统 内存暴涨分析 记一次 .NET 某RFID标签打印客户端 崩溃分析 对 .NET FileSystemWatcher引发内存碎片化的 反思 DotMemory系列:5. 如何实现自动化抓取和应用自托管 DotMemory系列:4. 如何分析进程的转储文件 DotMemory系列:3. 堆碎片化引发的内存暴涨分析 DotMemory系列:2. 事件泄露引发的内存暴涨分析 DotMemory系列:1. 终结队列积压引发的内存暴涨分析 记一次 .NET 某理财管理客户端 OOM溢出分析 记一次 .NET 某医联体管理系统 崩溃分析 记一次 .NET 某光放测试系统 崩溃分析 记一次 .NET 某药品缺陷高速检测系统 卡慢分析 聊一聊 .NET超高内存故障分析方法 的反思 记一次 .NET 某企业ECM内容管理系统 内存暴涨分析 记一次 .NET 某跨境物流系统 内存暴涨分析 记一次 .NET 某中医药附属医院门诊系统 崩溃分析 聊一聊 .NET 中的 CompositeChangeToken 聊一聊 .NET 中的 CancellationTokenSource 记一次 .NET 某CRM物流行业管理系统 崩溃分析
记一次 .NET 某电力后台监控系统 内存暴涨分析
一线码农 · 2026-07-14 · via 博客园 - 一线码农

一:背景

1. 讲故事

前些天有位朋友在微信上找到我,说他们的电力系统出现了内存暴涨的问题,让我帮忙看下怎么回事?由于不是训练营里的学员,所以这个分析能力还是有点门外汉,让这位朋友将dump丢给我,然后我们上windbg分析。

二:内存暴涨分析

1. 为什么会暴涨

要想知道为什么会涨,很简单,用老套路观察内存分布就行了,首先上 !address -summary 即可。


0:000> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                    206     7ffe`f5a2e000 ( 127.996 TB)          100.00%
<unknown>                               252        0`f9541000 (   3.896 GB)  93.61%    0.00%
Image                                  1070        0`0c047000 ( 192.277 MB)   4.51%    0.00%
Stack                                   195        0`03f80000 (  63.500 MB)   1.49%    0.00%
Heap                                     50        0`00e58000 (  14.344 MB)   0.34%    0.00%
Other                                    13        0`001df000 (   1.871 MB)   0.04%    0.00%
TEB                                      65        0`00082000 ( 520.000 kB)   0.01%    0.00%
PEB                                       1        0`00001000 (   4.000 kB)   0.00%    0.00%

--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE                             522        0`f9fd3000 (   3.906 GB)  93.85%    0.00%
MEM_IMAGE                              1075        0`0c06c000 ( 192.422 MB)   4.52%    0.00%
MEM_MAPPED                               49        0`04583000 (  69.512 MB)   1.63%    0.00%

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE                                206     7ffe`f5a2e000 ( 127.996 TB)          100.00%
MEM_COMMIT                             1360        0`f1915000 (   3.774 GB)  90.69%    0.00%
MEM_RESERVE                             286        0`18cad000 ( 396.676 MB)   9.31%    0.00%

接下来使用 !eeheap -gc 观察托管堆,这样就可以一分为二的则出问题。


0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000001d1803e6ee8
generation 1 starts at 0x000001d18038fc98
generation 2 starts at 0x000001d080001000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001d080000000  000001d080001000  000001d08fffffa0  0xfffefa0(268431264)
000001d098000000  000001d098001000  000001d0a7ffff58  0xfffef58(268431192)
000001d0a8000000  000001d0a8001000  000001d0b7ffff20  0xfffef20(268431136)
000001d0c0000000  000001d0c0001000  000001d0cffffd80  0xfffed80(268430720)
000001d0d8000000  000001d0d8001000  000001d0e7ffff28  0xfffef28(268431144)
000001d0fb7f0000  000001d0fb7f1000  000001d10b7effb8  0xfffefb8(268431288)
000001d10db60000  000001d10db61000  000001d11db5fe20  0xfffee20(268430880)
000001d11db60000  000001d11db61000  000001d12db5fcf0  0xfffecf0(268430576)
000001d12db60000  000001d12db61000  000001d13db5ff30  0xfffef30(268431152)
000001d13db60000  000001d13db61000  000001d14db5ffd8  0xfffefd8(268431320)
000001d14db60000  000001d14db61000  000001d15db5ffe8  0xfffefe8(268431336)
000001d15db60000  000001d15db61000  000001d16db5d040  0xfffc040(268419136)
000001d16db60000  000001d16db61000  000001d17db5ada0  0xfff9da0(268410272)
000001d17db60000  000001d17db61000  000001d1808f97b0  0x2d987b0(47810480)
Large object heap starts at 0x000001d090001000
         segment             begin         allocated              size
000001d090000000  000001d090001000  000001d0952f8028  0x52f7028(86994984)
000001d0d0000000  000001d0d0001000  000001d0d6958340  0x6957340(110457664)
Total Size:              Size: 0xde9d0d70 (3734834544) bytes.
------------------------------
GC Heap Size:            Size: 0xde9d0d70 (3734834544) bytes.

从卦中可以轻松的看出,obviously,当前是托管堆内存暴涨,接下来观察托管堆。


0:000> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
00007ffa6e7a1ec0        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.Int64, mscorlib]]
00007ffa6dc5e1e0        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]]
00007ffa6dc5e110        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.Int32, mscorlib]]
00007ffa6dc58a98        1           24 System.CLSCompliantAttribute
...
00007ffa1132a1e8   482984     88869056 xxx.C_Sys_UserAppTokenModel
00007ffa112f2488   602175    178243800 xxx.C_Sys_UserModel
00007ffa6dc41ac8   229351    238910824 System.String[]
00007ffa6dc59808 30618357   1297263358 System.String
000001d0ebefbff0  4003171   1418932312      Free
Total 41839190 objects
Fragmented blocks larger than 0.5 MB:
            Addr     Size      Followed by
000001d18060cca8    1.0MB 000001d180702c58 System.Byte[]
000001d180702ce8    0.5MB 000001d18078a340 System.Net.SocketAddress
000001d18078a3c0    1.4MB 000001d1808f9568 System.Byte[]

从卦中 bottom-up 来看,当前托管堆中貌似是 Free 导致的内存碎片化,接下来就是往内存碎片化这边 investigation。

2. 真的是free导致的碎片化吗

由于 free 的个数高达 400w +,直接观察free的前后是什么,这个有一点的实操难度,at this point 我们发现C_Sys_UserAppTokenModelC_Sys_UserModel 也高达48w和60w,虽不是很高,但也给我们留了是不是实体失控的模糊影子?

接下来祭出perfview观察这两哥们是不是来自于某个集合变量,截图如下:

image

image

从卦中可以清晰的看到,托管堆上有三个 static 变量,分别吃了1G,712M 和 282M,尤其是1G的 s_DeviceManager 集合,经过展开 perfview 是一个 ConcurrentDictionary<Int32, List<String>> 集合,能吃1G的ConcurrentDictionary,要么当缓存使用,要么就是失控。

有了这些概念之后,我们再次回望托管堆上的free 的前后数据,输出如下:


0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000001d1803e6ee8
generation 1 starts at 0x000001d18038fc98
generation 2 starts at 0x000001d080001000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001d080000000  000001d080001000  000001d08fffffa0  0xfffefa0(268431264)
000001d098000000  000001d098001000  000001d0a7ffff58  0xfffef58(268431192)
000001d0a8000000  000001d0a8001000  000001d0b7ffff20  0xfffef20(268431136)
000001d0c0000000  000001d0c0001000  000001d0cffffd80  0xfffed80(268430720)
000001d0d8000000  000001d0d8001000  000001d0e7ffff28  0xfffef28(268431144)
000001d0fb7f0000  000001d0fb7f1000  000001d10b7effb8  0xfffefb8(268431288)
000001d10db60000  000001d10db61000  000001d11db5fe20  0xfffee20(268430880)
000001d11db60000  000001d11db61000  000001d12db5fcf0  0xfffecf0(268430576)
000001d12db60000  000001d12db61000  000001d13db5ff30  0xfffef30(268431152)
000001d13db60000  000001d13db61000  000001d14db5ffd8  0xfffefd8(268431320)
000001d14db60000  000001d14db61000  000001d15db5ffe8  0xfffefe8(268431336)
000001d15db60000  000001d15db61000  000001d16db5d040  0xfffc040(268419136)
000001d16db60000  000001d16db61000  000001d17db5ada0  0xfff9da0(268410272)
000001d17db60000  000001d17db61000  000001d1808f97b0  0x2d987b0(47810480)
Large object heap starts at 0x000001d090001000
         segment             begin         allocated              size
000001d090000000  000001d090001000  000001d0952f8028  0x52f7028(86994984)
000001d0d0000000  000001d0d0001000  000001d0d6958340  0x6957340(110457664)
Total Size:              Size: 0xde9d0d70 (3734834544) bytes.
------------------------------
GC Heap Size:            Size: 0xde9d0d70 (3734834544) bytes.


0:000> !dumpheap 000001d10db61000  000001d11db5fe20
...
000001d10db62408 00007ffa11436458      272     
000001d10db62518 00007ffa114365d8       48     
000001d10db62548 000001d0ebefbff0      422 Free
000001d10db626f0 00007ffa6d54ac78       40     
000001d10db62718 00007ffa6dc59808       34     
000001d10db62740 00007ffa6dc59808       34     
000001d10db62768 000001d0ebefbff0      110 Free
000001d10db627d8 00007ffa6d54ac78       40     
000001d10db62800 00007ffa6dc59808       34     
000001d10db62828 00007ffa6dc59808       34     
...

0:000> !gcroot 000001d10db62740
Thread 2aa0:
    000000a1905be300 00007ffa1112fead xxx.C_DeviceManager.<xxxDicTODB>b__30_0()
        rbp+10: 000000a1905be3b0
            ->  000001d0805121a8 xxx.C_DeviceManager
            ->  000001d080512200 System.Collections.Concurrent.ConcurrentDictionary`2[[System.Int32, mscorlib],[System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib]]
            ->  000001d142690a08 System.Collections.Concurrent.ConcurrentDictionary`2+Tables[[System.Int32, mscorlib],[System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib]]
            ->  000001d0912a9958 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Int32, mscorlib],[System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib]][]
            ->  000001d14250af68 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Int32, mscorlib],[System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib]]
            ->  000001d10db626f0 System.Collections.Generic.List`1[[System.String, mscorlib]]
            ->  000001d116e68958 System.String[]
            ->  000001d10db62740 System.String

最后我们到 <xxxDicTODB>b__30_0 中找相关的代码逻辑,由于隐私关系这里就不显示了,让朋友去看下 <xxxDicTODB>b__30_0 中为什么把 ConcurrentDictionary 搞这么大,最后朋友发现是 TODB 过程中的数据堆积所致,而这个堆积又引发了托管堆的碎片化,有点意思。

三:总结

这次生产事故是因为业务逻辑问题导致内存static堆积,而堆积又引发了堆碎片化,所以这个dump在分析时有一定的误导性,很多人往往会被 free 给先入为主了。。。

图片名称