尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

记一次 .NET 某理财管理客户端 OOM溢出分析

记一次 .NET 某理财管理客户端 OOM溢出分析
📅 发布时间:2026/6/18 2:55:13

一:背景

1. 讲故事

这是训练营里的学员找到我的,让我帮忙看下为什么他的客户程序会偶发的出现 报错弹框,由于dump比较敏感,这里就不截图发出来了,由于是错误弹框,并不会出现程序崩溃,而且朋友在日志中也看到了 OOM 异常,就是因为这个 OOM 异常导致了后续流程的 报错弹框,说这个程序的内存还行,在业务代码中用了 try catch 吞掉异常了,让我帮忙看下。

由于 OOM dump没到手,而且代码中使用 try catch 吞掉了,有些人可能就没撤了,其实知道 异常两阶段 的朋友应该知道,我们可以在 first chance 的时候抓dump,即 catch 之前,所以就有了下面的捕获脚本。


procdump 20860 -e 1 -f PAVException -ma -o D:\testdump\

顺利拿到dump之后,接下来就是一顿分析了。

二:OOM分析

1. 为什么会 OOM

双击 dump 之后,映入眼帘的就是异常线程的现场信息,参考如下:


This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(15fc.4fe8): C++ EH exception - code e06d7363 (first/second chance not available)
For analysis of this file, run !analyze -v
eax=2b1aefa0 ebx=19930520 ecx=00000003 edx=00000000 esi=037eebc0 edi=530bb548
eip=77383874 esp=2b1aefa0 ebp=2b1aeffc iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
KERNELBASE!RaiseException+0x64:
77383874 8b4c2454        mov     ecx,dword ptr [esp+54h] ss:002b:2b1aeff4=224e4fd8

从卦中可以看到 RaiseException 就是托管异常的明证,接下来用 .ecxr ; k 观察异常调用栈。


0:052> .ecxr;k 
eax=2b1aefa0 ebx=19930520 ecx=00000003 edx=00000000 esi=037eebc0 edi=530bb548
eip=77383874 esp=2b1aefa0 ebp=2b1aeffc iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
KERNELBASE!RaiseException+0x64:
77383874 8b4c2454        mov     ecx,dword ptr [esp+54h] ss:002b:2b1aeff4=224e4fd8*** Stack trace for last set context - .thread/.cxr resets it# ChildEBP RetAddr      
00 2b1aeffc 52e3c8fb     KERNELBASE!RaiseException+0x64
01 2b1af02c 52fee8fc     coreclr!_CxxThrowException+0x66 [d:\a01\_work\11\s\src\vctools\crt\vcruntime\src\eh\throw.cpp @ 74] 
02 2b1af040 52d481a8     coreclr!ThrowOutOfMemory+0x24 [D:\a\_work\1\s\src\coreclr\src\utilcode\ex.cpp @ 1044] 
03 2b1af074 30b8f91e     coreclr!LargeHeapHandleTable::AllocateHandles [D:\a\_work\1\s\src\coreclr\src\vm\appdomain.cpp @ 381] 
WARNING: Frame IP not in any known module. Following frames may be wrong.
04 2b1af074 05990114     0x30b8f91e
05 2b1af074 52d452e7     0x5990114
06 2b1af0c8 52d453e7     coreclr!AllocateSzArray+0x227 [D:\a\_work\1\s\src\coreclr\src\vm\gchelpers.cpp @ 427] 
07 2b1af14c 5257296e     coreclr!JIT_NewArr1+0xb7 [D:\a\_work\1\s\src\coreclr\src\vm\jithelpers.cpp @ 2723] 
08 2b1af160 52581bcf     System_Private_CoreLib!System.Text.Encoding.GetBytes+0x22 [_/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @ 667] 
09 2b1af168 263e7ad6     System_Private_CoreLib!System.Text.UTF8Encoding.UTF8EncodingSealed.GetBytes+0x1b
0a 2b1af1a8 263e7a43     xxx!xxx.xxxxHashData+0x46

从卦中可以清晰的看到,原来是在 xxxxHashData 中执行了 GetBytes 时抛出的 OOM 异常, 那为什么 GetBytes 会抛出异常呢?这个只能结合源代码说话了。

2. GetBytes 为什么会抛出 OOM

找到 xxxxHashData 下的 GetBytes 方法,截图如下:

从卦中可以看到参数是一个 string,看样子这就是突破口了,使用 !clrstack -a 观察这个 s 的具体值,参考如下:


0:052> !clrstack -a
OS Thread Id: 0x4fe8 (52)
Child SP       IP Call Site
2B1AF0E8 77383874 [HelperMethodFrame: 2b1af0e8] 
2B1AF154 5257296e System.Text.Encoding.GetBytes(System.String) [/_/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @ 667]PARAMETERS:this (<CLR reg>) = 0x05b5b674s (<CLR reg>) = 0x348d1010LOCALS:<no data><no data><no data>0:052> !DumpObj /d 348d1010
Name:        System.String
MethodTable: 0568ec98
EEClass:     0569a8c0
Size:        83886094(0x500000e) bytes
String:      <String is invalid or too large to print>
Fields:MT    Field   Offset                 Type VT     Attr    Value Name
056873b4  4000212        4         System.Int32  1 instance 41943040 _stringLength
056854e0  4000213        8          System.Char  1 instance       54 _firstChar
0568ec98  4000211       60        System.String  0   static 05b512b0 Empty0:052> ? 0x500000e
Evaluate expression: 83886094 = 0500000e

从卦中看真的是吓一跳,string.length=4194w 真尼玛大,并且 string 的重量高达 83M,就是由于这个 83M 的string,被 clr 直接给屏掉了。。。接下来的问题是为什么 clr 会屏掉呢?

3. clr 为什么会屏掉

有一些 clr 基础知识的朋友应该知道,这种 OOM 异常一般是两种情况。

  1. 通过 if 语句判断是否超限,这个在训练营里面都有讲到,参考代码如下:
// Limit the maximum string size to <2GB to mitigate risk of security issues caused by 32-bit integer// overflows in buffer size calculations.if (cchStringLength > CORINFO_String_MaxLength)ThrowOutOfMemory();
  1. 向托管堆要指定大小的内存要不到的时候,这个可以用 !ao 命令观察。

0:052> !ao
Didn't have enough memory to allocate an LOH segment
Details: LOH Failed to reserve memory 50,331,648 bytes

从上面的卦数据来看,是 clr 向大对象堆预定50M的连续地址空间时,结果要不到,clr非常无奈抛出了这个OOM异常。

接下来的问题是为什么要不到呢?

4. 为什么托管堆拒绝了

有经验的朋友应该知道是咋回事了,对,就是虚拟地址空间不足导致的。。。 可以用 !address -summary 观察虚拟地址空间大小。


0:052> !address -summary--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown>                              1091          3e78b000 ( 999.543 MB)  64.47%   48.81%
Free                                    380          1f183000 ( 497.512 MB)           24.29%
Image                                  1039          17d37000 ( 381.215 MB)  24.59%   18.61%
Stack                                   219           6100000 (  97.000 MB)   6.26%    4.74%
Heap                                     38           4751000 (  71.316 MB)   4.60%    3.48%
TEB                                      73            11a000 (   1.102 MB)   0.07%    0.05%
Other                                    21             3d000 ( 244.000 kB)   0.02%    0.01%
PEB                                       1              3000 (  12.000 kB)   0.00%    0.00%--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE                            1010          36608000 ( 870.031 MB)  56.12%   42.48%
MEM_IMAGE                              1142          17e6c000 ( 382.422 MB)  24.67%   18.67%
MEM_MAPPED                              330          129f9000 ( 297.973 MB)  19.22%   14.55%--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT                             1937          4fdd5000 (   1.248 GB)  82.42%   62.40%
MEM_FREE                                380          1f183000 ( 497.512 MB)           24.29%
MEM_RESERVE                             545          11098000 ( 272.594 MB)  17.58%   13.31%

从卦中可以看到虽然 MEM_RESERVE=272M ,但没有哪一块是大于 50M 的,所以直接导致灾难的发生,到这里该如何解决呢?这其实也是一个经典的问题,即 32bit 程序 2G 地址空间问题,修改办法如下:

  1. 使用大地址 LargeAddress,让程序尽量吃 4G 内存。
  2. 将程序调整到 64bit,让虚拟地址不再捉襟见肘。

三:总结

这个故障也不算是什么大问题,就像网络时好时坏一样,不过像这种强势部门投放过来的抱怨也是亚历山大的。。。

图片名称

相关新闻

  • P14400 [JOISC 2016] 回转寿司 / Sushi
  • 灰度的openkruise rollout - Super
  • P6532 [COCI 2015/2016 #1] TOPOVI

最新新闻

  • Totolink路由器未授权访问漏洞:原理、复现与安全加固实战
  • 佛山出手翡翠别乱选!本地高口碑回收商家排行榜来了 - 奢侈品交易观察员
  • 如何解决Buzz离线转录工具的模型下载难题:终极加速指南
  • 混淆矩阵实战指南:从医疗诊断看分类模型评估本质
  • AI Studio实战指南:从提示词到可交付产品的完整工作流
  • 30+种音视频格式全免费转!2026在线保姆级大合集,这一篇够了 - 时时资讯

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号