• 记一次 .NET 某零售管理系统 存储不足分析


    一:背景

    1. 讲故事

    前几天有位朋友找到我,说他的程序会偶发性的报 存储空间不足,无法处理此命令 的错误,让我帮忙看下到底怎么回事,哈哈,人家是有备而来,dump都准备好了,话不多说,直接分析开干。

    二:WinDbg 分析

    1. 捕获dump中的异常

    一般来讲别人说的只是一个参考,我们需要自己到dump中去验证,可以用 !t 观察下。

    
    0:000:x86> !t
    ThreadCount:      61
    UnstartedThread:  0
    BackgroundThread: 52
    PendingThread:    0
    DeadThread:       3
    Hosted Runtime:   no
                                                                             Lock  
           ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
       0    1 9310 004e24f8     26020 Preemptive  00000000:00000000 004d94e0 0     STA System.Runtime.InteropServices.COMException 42b57774 (nested exceptions)
       ...
    
    0:000:x86> !PrintException /d 42b57774
    Exception object: 42b57774
    Exception type:   System.Runtime.InteropServices.COMException
    Message:          存储空间不足,无法处理此命令。 (Exception from HRESULT: 0x80070008)
    InnerException:   
    StackTrace (generated):
        SP       IP       Function
        00000000 00000001 mscorlib_ni!System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32, IntPtr)+0x2
        003FAC0C 6F5655C9 mscorlib_ni!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32, IntPtr)+0x9
        003FAC10 55171671 PresentationCore_ni!MS.Internal.Text.TextInterface.Native.Util.ConvertHresultToException(Int32)+0x702961
        003FAC24 54A56129 PresentationCore_ni!MS.Internal.Text.TextInterface.FontFace.GetDesignGlyphMetrics(UInt16*, UInt32, MS.Internal.Text.TextInterface.GlyphMetrics*)+0x79
        003FAC60 54A73B77 PresentationCore_ni!System.Windows.Media.GlyphTypeface.GlyphMetrics(UInt16*, Int32, MS.Internal.Text.TextInterface.GlyphMetrics*, Double, System.Windows.Media.TextFormattingMode, Boolean)+0x47
        ...
    
    

    从卦中信息看确实抛了一个 COMException 异常,并且真的有这么一条错误信息 存储空间不足,无法处理此命令,而且从调用栈来看貌似是wpf在处理 字形信息,一般来说这种代码是千锤百炼不会出任何问题的。

    作为现代化的程序员,必须通过 百度搜索 寻找一下天涯沦落人,通过搜索得知大概有两种情况:

    • 硬盘存储空间不足所致
    • 内存不足所致

    2. 是硬盘存储空间不足吗

    要想验证是不是这种情况导致的,只能询问下朋友,据朋友反馈不存在这个问题,所以这条路就堵死了。

    3. 是内存不足吗

    要想排查这种情况只能观察进程的 MEM_COMMIT 指标,使用 !address -summary

    
    0:000:x86> !address -summary
    ...
    --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
    MEM_COMMIT                             3773          6e617000 (   1.725 GB)  89.86%   86.24%
    MEM_RESERVE                             702           c4c6000 ( 196.773 MB)  10.01%    9.61%
    MEM_FREE                                667           5513000 (  85.074 MB)            4.15%
    ...
    --- Largest Region by Usage ----------- Base Address -------- Region Size ----------
    Heap32                                      23470000            fd0000 (  15.812 MB)
                                       474b0000           19c4000 (  25.766 MB)
    Image                                       2fbf1000           1180000 (  17.500 MB)
    Free                                        7355b000            1a5000 (   1.645 MB)
    Stack32                                       c50000             fd000 (1012.000 kB)
    Stack64                                       5a0000             39000 ( 228.000 kB)
    Other                                         8e0000            181000 (   1.504 MB)
    TEB64                                       7ee37000              2000 (   8.000 kB)
    Heap64                                        120000             65000 ( 404.000 kB)
    TEB32                                       7ee39000              1000 (   4.000 kB)
    Other32                                       290000              1000 (   4.000 kB)
    PEB64                                       7efdf000              1000 (   4.000 kB)
    PEB32                                       7efde000              1000 (   4.000 kB)
    ...
    
    

    从卦中的信息看,当前程序提交内存是 1.7G ,看到这个值马上就想到了 2G虚拟地址,那这个程序是不是x86的呢?除了观察内存地址,也可以通过观察 PE 头获知。

    
    0:000:x86> lm 
    start    end        module name
    01380000 01450000   xxxWinApp C (no symbols)       
    
    0:000:x86> !dh xxxWinApp 
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
         14C machine (i386)
           3 number of sections
    654073AD time date stamp Tue Oct 31 11:25:33 2023
    
           0 file pointer to symbol table
           0 number of symbols
          E0 size of optional header
         102 characteristics
                Executable
                32 bit word machine
    
    

    从卦中的 32 bit word machine 来看,确实没有开大地址,看样子是受到了 2G 的虚拟地址限制。

    不过说实话我真的佩服写这个软件的程序员,在上限 2G 的空间内,能将程序控制在 1.72G 都不崩,把内存压得严严实实,确实🐂👃。

    4. 如何开启大地址

    开启大地址非常简单,可以用 DnSpy 打开我们的应用程序,然后勾选 Large Address Aware 选项,修改完之后进行保存,截图如下:

    最后一个问题是开启后他的程序可以吃到 3G 还是 4G 呢?这个取决于是 x64 还是 x86 的操作系统,可以用 vertarget 观察。

    
    0:000:x86> vertarget
    Windows 7 Version 7601 (Service Pack 1) MP (4 procs) Free x64
    Product: WinNt, suite: SingleUserTS
    Edition build lab: kernel32.dll version: 6.1.7601.24545 (win7sp1_ldr_escrow.200102-1707)
    Debug session time: Mon Nov 27 11:10:18.000 2023 (UTC + 8:00)
    System Uptime: 5 days 8:49:46.984
    Process Uptime: 1 days 0:50:00.000
      Kernel time: 0 days 0:06:48.000
      User time: 0 days 0:24:11.000
    
    

    从卦中的 Windows 7 Version 7601 (Service Pack 1) MP (4 procs) Free x64 可知当前是 Windows7 x64 版本,即可以吃到 4G 内存,基本上就能解决这个问题。

    三:总结

    一般来说这种错误:存储空间不足,无法处理此命令 基本上 98% 都是内存空间不足导致的,只有 2% 的情况真的是 硬盘不足

    这个dump最有价值的地方在于没有纠结于 COMException 异常,并且在没有抛出 OutofMemoryException 异常的前提前定位出问题所在。

    图片名称
  • 相关阅读:
    【廉颇老矣,尚能饭否】传统的数据仓库是否还能发挥作用?
    华为终于要“三分天下”
    NX二次开发-使用NXOpen::DisplayModification类,将UF曲线-面-体等tag设置颜色
    Android6.0+修改通知栏与页面样式保持一致
    数据库实验3答案
    [附源码]Python计算机毕业设计Django健身房信息管理
    ss(socket statistics)和netstat获取网络连接的实现
    首家上市的量子计算软件公司!Zapata AI拟完成SPAC交易
    leetcode 刷题 log day 44
    VB.NET 三层登录系统实战:从设计到部署全流程详解
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/17879166.html