iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > ASP.NET >.NETWindbg分析某妇产医院WPF内存溢出
  • 941
分享到

.NETWindbg分析某妇产医院WPF内存溢出

2024-04-02 19:04:59 941人浏览 安东尼
摘要

目录一:背景1. 讲故事二:Windbg 分析1. 为什么会内存溢出2. 探索溢出原因3. 如何突破 2G 限制三:总结一:背景 1. 讲故事 上个月有位朋友找到我,说他的程序存在内

一:背景

1. 讲故事

上个月有位朋友找到我,说他的程序存在内存溢出情况,寻求如何解决。

要解决还得通过 windbg 分析啦。

二:Windbg 分析

1. 为什么会内存溢出

大家都知道内存溢出对应着 .net 中的 OutOfMemoryException 异常,这种异常有可能是托管代码手工抛出的,也有可能是CLR层面抛出的,言外之意就是可以通过两种方式排查。

  • 托管线程是否挂载着异常?
0:000> !t
ThreadCount:      23
UnstartedThread:  0
BackgroundThread: 5
PendingThread:    0
DeadThread:       17
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
   0    1 362c 00fac868     26020 Preemptive  7ED701A0:00000000 00fa6b60 0     STA 
   5    2 2d70 00fbeba0     2b220 Preemptive  7EBA7AC0:00000000 00fa6b60 0     MTA (Finalizer) 
   7    3 3264 061c8890   102a220 Preemptive  00000000:00000000 00fa6b60 0     MTA (Threadpool Worker) 
  17   15 3f98 19682b90   202b220 Preemptive  7EBB0830:00000000 00fa6b60 0     MTA 
XXXX   16    0 2845fb00     35820 Preemptive  00000000:00000000 00fa6b60 0     Ukn 
  18   14  a7c 2842b1c8   202b220 Preemptive  00000000:00000000 00fa6b60 0     MTA 
XXXX    6    0 2c9b3778   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   18    0 288a1318   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   23    0 288a22f0   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   10    0 2ccf3550   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   21    0 288a1860   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   12    0 288a1da8   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   11    0 2c993640   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX    8    0 2ccf3a98     35820 Preemptive  00000000:00000000 00fa6b60 0     Ukn 
XXXX    9    0 2ccf2030   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX    7    0 2c9aed88   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   26    0 28898308   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   25    0 2c492c68   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX    4    0 2c993b88   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   20    0 2c9af2d0   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   17    0 2c9afd60   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
XXXX   24    0 2c9b1280   1039820 Preemptive  00000000:00000000 00fa6b60 0     Ukn (Threadpool Worker) 
  23   22 2658 2c9b02a8   1029220 Preemptive  7ED5BFF8:00000000 00fa6b60 0     MTA (Threadpool Worker) 

从输出信息看,这些线程并没有挂载任何托管异常,我去。。。

  • 是否在 CLR 上抛出

这主要是看 托管堆(heap) 上的内存分配或者gc回收造成的内存不足,可以用 !ao 命令。

0:000> !ao
There was no managed OOM due to allocations on the GC heap

从输出信息看也没有任何异常,尴尬了???。。。 尼玛,那到底是因为什么呢?

2. 探索溢出原因

出现这种尴尬情况,我只能怀疑生成这个dump的时候并没有get到那个点,或者是我的知识边界有限,不过天无绝人之路,不在那个 点 也肯定在那个 点 附近,对吧,接下来用 !address -summary 看一下内存使用的归类信息。

0:000> !address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown>                              1520          4c185000 (   1.189 GB)  65.57%   59.45%
Image                                  4306          1f140000 ( 497.250 MB)  26.78%   24.28%
Free                                   1133           bf17000 ( 191.090 MB)            9.33%
Heap                                    617           7626000 ( 118.148 MB)   6.36%    5.77%
Stack                                    72           1740000 (  23.250 MB)   1.25%    1.14%
Other                                    34             7b000 ( 492.000 kB)   0.03%    0.02%
TEB                                      24             30000 ( 192.000 kB)   0.01%    0.01%
PEB                                       1              3000 (  12.000 kB)   0.00%    0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_MAPPED                              549          34b60000 ( 843.375 MB)  45.42%   41.18%
MEM_PRIVATE                            1718          20424000 ( 516.141 MB)  27.80%   25.20%
MEM_IMAGE                              4307          1f155000 ( 497.332 MB)  26.78%   24.28%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT                             4904          66DDD000 (   1.607 GB)  88.64%   80.37%
MEM_RESERVE                            1670           d2fc000 ( 210.984 MB)  11.36%   10.30%
MEM_FREE                               1133           bf17000 ( 191.090 MB)            9.33%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READONLY                          2272          382cf000 ( 898.809 MB)  48.41%   43.89%
PAGE_READWRITE                         1572          1eead000 ( 494.676 MB)  26.64%   24.15%
PAGE_EXECUTE_READ                       218           dd59000 ( 221.348 MB)  11.92%   10.81%
PAGE_WRITECOPY                          449           133e000 (  19.242 MB)   1.04%    0.94%
PAGE_EXECUTE_READWRITE                  188            ab4000 (  10.703 MB)   0.58%    0.52%
PAGE_NOACCESS                           156             9c000 ( 624.000 kB)   0.03%    0.03%
PAGE_READWRITE | PAGE_GUARD              48             78000 ( 480.000 kB)   0.03%    0.02%
PAGE_READWRITE | PAGE_WRITECOMBINE        1              2000 (   8.000 kB)   0.00%    0.00%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
<unknown>                                   1d200000           a001000 ( 160.004 MB)
Image                                        fed1000           36e4000 (  54.891 MB)
Free                                        33Dfe000           1082000 (  16.508 MB)
Heap                                        3da84000            a1b000 (  10.105 MB)
Stack                                        1a10000             fd000 (1012.000 kB)
Other                                       7fa40000             33000 ( 204.000 kB)
TEB                                           a4c000              3000 (  12.000 kB)
PEB                                           a3d000              3000 (  12.000 kB)

从上面的 MEM_COMMIT=1.607 GB 80.37% 信息看,当前内存占用 1.6G,占比 80.37%,可以看出它受到了一个 2G内存 的限制,而且从 !t 输出中的内存地址看,当前是 32bit 程序,所以这是一个经典的: 64系统跑着32位程序被2G内存限制 的问题。

3. 如何突破 2G 限制

要寻找答案,还得看最权威的 MSDN: 

https://docs.microsoft.com/en-us/windows/win32/memory/memory-limits-for-windows-releases?redirectedfrom=MSDN

破局 还得设置程序的 IMAGE_FILE_LARGE_ADDRESS_AWARE 标记。

关于具体怎么设置,我找了三种方法。

  • 使用 LargeAddressAware 安装包

参见 GitHub: 

Https://github.com/KirillOsenkov/LargeAddressAware

  • 使用 editbin

可以在 vs 的生成事件中输入 editbin /largeaddressaware $(TargetPath)。

  • 使用代码方式

这种可以直接给生成好的 exe 增加 LargeAddressAware 标记,除了标记,还能检测,??

using System;
using System.IO;
namespace PEFile
{
    public class LargeAddressAware
    {
        public static bool IsLargeAddressAware(string filePath)
        {
            bool isLargeAddressAware = false;
            PrepareStream(filePath, (stream, binaryReader) => isLargeAddressAware = (binaryReader.ReadInt16() & 0x20) != 0);
            return isLargeAddressAware;
        }
        public static void SetLargeAddressAware(string filePath)
        {
            PrepareStream(filePath, (stream, binaryReader) =>
            {
                var value = binaryReader.ReadInt16();
                if ((value & 0x20) == 0)
                {
                    value = (short)(value | 0x20);
                    stream.Position -= 2;
                    var binaryWriter = new BinaryWriter(stream);
                    binaryWriter.Write(value);
                    binaryWriter.Flush();
                }
            });
        }
        private static void PrepareStream(string filePath, Action<Stream, BinaryReader> action)
        {
            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            {
                if (stream.Length < 0x3C)
                {
                    return;
                }
                var binaryReader = new BinaryReader(stream);
                // MZ header
                if (binaryReader.ReadInt16() != 0x5A4D)
                {
                    return;
                }
                stream.Position = 0x3C;
                var peHeaderLocation = binaryReader.ReadInt32();
                stream.Position = peHeaderLocation;
                // PE header
                if (binaryReader.ReadInt32() != 0x4550)
                {
                    return;
                }
                stream.Position += 0x12;
                action(stream, binaryReader);
            }
        }
    }
}

更多办法参考:

https://stackoverflow.com/questions/639540/how-much-memory-can-a-32-bit-process-access-on-a-64-bit-operating-system

三:总结

总的来说,2G 内存限制 是一个 32bit 程序所必须面对的问题,知道了就好解决了,最后有一个问题要解释下,为什么 commit 内存高达 1.6G,这是因为医疗类的软件,大多是 FastReport + DevExpress 这些重量级的经典搭配以及大量的图片资源占用了太多 native memory。

以上就是.NET Windbg分析某妇产医院WPF内存溢出的详细内容,更多关于.NET Windbg WPF内存溢出的资料请关注编程网其它相关文章!

--结束END--

本文标题: .NETWindbg分析某妇产医院WPF内存溢出

本文链接: https://www.lsjlt.com/news/150489.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • .NETWindbg分析某妇产医院WPF内存溢出
    目录一:背景1. 讲故事二:Windbg 分析1. 为什么会内存溢出2. 探索溢出原因3. 如何突破 2G 限制三:总结一:背景 1. 讲故事 上个月有位朋友找到我,说他的程序存在内...
    99+
    2024-04-02
  • 怎么使用.NET Windbg分析某妇产医院WPF内存溢出问题
    本篇内容主要讲解“怎么使用.NET Windbg分析某妇产医院WPF内存溢出问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用.NET Windbg分析某妇产医院WP...
    99+
    2023-06-30
  • Java内存溢出和内存泄露的示例分析
    这篇文章给大家分享的是有关Java内存溢出和内存泄露的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、为什么要了解内存泄露和内存溢出?内存泄露一般是代码设计存在缺陷导致的,通过了解内存泄露的场景,可以避...
    99+
    2023-05-30
    java
  • Disruptor发生内存溢出的示例分析
    今天给大家介绍一下Disruptor发生内存溢出的示例分析。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。前言OutOfMemoryError 问题相...
    99+
    2023-06-04
  • JVM中内存区域与内存溢出的示例分析
    小编给大家分享一下JVM中内存区域与内存溢出的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java内存区域与内存溢出异常运行时数据区域程序计数器当前线程...
    99+
    2023-06-17
  • Java8虚拟机内存溢出的示例分析
    这篇文章给大家分享的是有关Java8虚拟机内存溢出的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。 Java8虚拟机(JVM)内存溢出实战 前言 相信很多JAVA中...
    99+
    2024-04-02
  • java内存管理与内存溢出异常的示例分析
    这篇文章主要介绍了java内存管理与内存溢出异常的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。说到内存管理,笔者这里想先比较一下java与C、C++之间的区别:在C...
    99+
    2023-05-31
    java
  • Tomcat运行Java Web内存溢出的示例分析
    这篇文章主要介绍Tomcat运行Java Web内存溢出的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!如果JVM里运行的程序, 它的内存堆和持久存储区域的都满了,这个时候程序还想创建对象实例的话,垃圾收集器...
    99+
    2023-06-17
  • Java 内存溢出(二)使用 MAT 分析 .hprof 内存映像文件
    目录 一、内存溢出时自动导出 .hprof 文件二、下载安装 MAT三、启动 MAT四、MAT 分析 hprof 文件1.Overview 概览2.Leak Suspects 溢出原因猜测3.Histogram 对象实例数量排序4....
    99+
    2023-08-18
    java jvm 开发语言
  • Java编程常见内存溢出异常的示例分析
    小编给大家分享一下Java编程常见内存溢出异常的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java 堆是用来存储对象实例的, 因此如果我们不断地创建对...
    99+
    2023-05-30
    java
  • Java服务假死后续之内存溢出的原因分析
    目录一、现象分析二、原因排查三、故障解决一、现象分析 上篇博客说到,Java服务假死的原因是使用了Guava缓存,30分钟的有效期导致Full GC无法回收内存。经过优化后,已经不再...
    99+
    2024-04-02
  • 一文教会你使用jmap和MAT进行堆内存溢出分析
    jmap:Java内存映像工具 jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。另外,还有几种方式获取dump文件...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作