Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 677|回复: 0

C#使用MiniDump捕获异常

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-8 17:14:09 | 显示全部楼层 |阅读模式

    c/c++语言里MiniDump是一个重要的调试手段,他们没有C#/java这样语言有很多异常输出信息(

    JVM异常导出bug日志功能,通常在jdk目录,文件格式hs_err_%pid%.log,pid是进程id)。

    我们通常在项目中都会把可预见性进行异常处理。常见的处理方法如下

    try{
    
       ...
    
    
    catch(Exception ex)
    {
       HandleExeption(ex);
    }

    项目部署到客户机中运行在程序员无法评估的情况下,如(堆栈溢出、访问冲突)则无法处理

    或者很难重现这种异常,这给程序调试带来一定程度上的障碍,而这个时候内存及当前机器环境的快

    照信息对程序排错则至关重要。幸好我们.NET提供了应用程序域未捕获异常(不是所有异常)事件处理

    接口AppDomain.UnhandledException先贴出Minidump封装类:

    public sealed class MiniDump
        {
            [Flags]
            public enum DumpType : uint
            {
                // From dbghelp.h:
                MiniDumpNormal = 0x00000000,
                MiniDumpWithDataSegs = 0x00000001,
                MiniDumpWithFullMemory = 0x00000002,
                MiniDumpWithHandleData = 0x00000004,
                MiniDumpFilterMemory = 0x00000008,
                MiniDumpScanMemory = 0x00000010,
                MiniDumpWithUnloadedModules = 0x00000020,
                MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
                MiniDumpFilterModulePaths = 0x00000080,
                MiniDumpWithProcessThreadData = 0x00000100,
                MiniDumpWithPrivateReadWriteMemory = 0x00000200,
                MiniDumpWithoutOptionalData = 0x00000400,
                MiniDumpWithFullMemoryInfo = 0x00000800,
                MiniDumpWithThreadInfo = 0x00001000,
                MiniDumpWithCodeSegs = 0x00002000,
                MiniDumpWithoutAuxiliaryState = 0x00004000,
                MiniDumpWithFullAuxiliaryState = 0x00008000,
                MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
                MiniDumpIgnoreInaccessibleMemory = 0x00020000,
                MiniDumpValidTypeFlags = 0x0003ffff,
            };
    
            //typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
            //    DWORD ThreadId;
            //    PEXCEPTION_POINTERS ExceptionPointers;
            //    BOOL ClientPointers;
            //} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
            [StructLayout(LayoutKind.Sequential, Pack = 4)]  // Pack=4 is important! So it works also for x64!
            struct MiniDumpExceptionInformation
            {
                public uint ThreadId;
                public IntPtr ExceptioonPointers;
                [MarshalAs(UnmanagedType.Bool)]
                public bool ClientPointers;
            }
    
            //BOOL
            //WINAPI
            //MiniDumpWriteDump(
            //    __in HANDLE hProcess,
            //    __in DWORD ProcessId,
            //    __in HANDLE hFile,
            //    __in MINIDUMP_TYPE DumpType,
            //    __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
            //    __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
            //    __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam
            //    );
            [DllImport("dbghelp.dll",
              EntryPoint = "MiniDumpWriteDump",
              CallingConvention = CallingConvention.StdCall,
              CharSet = CharSet.Unicode,
              ExactSpelling = true, SetLastError = true)]
            static extern bool MiniDumpWriteDump(
              IntPtr hProcess,
              uint processId,
              IntPtr hFile,
              uint dumpType,
              ref MiniDumpExceptionInformation expParam,
              IntPtr userStreamParam,
              IntPtr callbackParam);
    
            [DllImport("kernel32.dll", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
            static extern uint GetCurrentThreadId();
    
            [DllImport("kernel32.dll", EntryPoint = "GetCurrentProcess", ExactSpelling = true)]
            static extern IntPtr GetCurrentProcess();
    
            [DllImport("kernel32.dll", EntryPoint = "GetCurrentProcessId", ExactSpelling = true)]
            static extern uint GetCurrentProcessId();
    
            public static bool Write(string fileName)
            {
                return Write(fileName, DumpType.MiniDumpWithFullMemory);
            }
            public static bool Write(string fileName, DumpType dumpType)
            {
                using (var fs = new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
                {
                    MiniDumpExceptionInformation exp;
                    exp.ThreadId = GetCurrentThreadId();
                    exp.ClientPointers = false;
                    exp.ExceptioonPointers = System.Runtime.InteropServices.Marshal.GetExceptionPointers();
                    bool bRet = MiniDumpWriteDump(
                      GetCurrentProcess(),
                      GetCurrentProcessId(),
                      fs.SafeFileHandle.DangerousGetHandle(),
                      (uint)dumpType,
                      ref exp,
                      IntPtr.Zero,
                      IntPtr.Zero);
                    return bRet;
                }
            }

     

    以下以Winform演示这个事件的使用方法

    先拖一个界面如下

     

    class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            static void Main(string[] args)
            {                      
                //exception handler
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
                Application.ThreadException += Application_ThreadException;
    
    
    
                bool isRunWinService = args.Length > 0 && args[0].ToLower().Equals("-service");
                //用户手工启动
                if (!isRunWinService)
                {
                    Application.Run(new frmSetup());
                }
                else
                {                             
                    ServiceBase.Run(new ServiceBase[] {
                        new Daemon()
                    });
                }
            }
    
            private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
            {
                string dumpFile = System.IO.Path.Combine(System.Environment.CurrentDirectory, string.Format("crash-dump-{0}.dmp", DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss")));
                MiniDump.Write(dumpFile);
            }
    
            private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                string dumpFile = System.IO.Path.Combine(System.Environment.CurrentDirectory, string.Format("thread-dump-{0}.dmp", DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss")));
                MiniDump.Write(dumpFile);
            }
        }

     两个按钮事件代码分别如下:

    private void button1_Click(object sender, EventArgs e)
            {
                new Thread(() => { throw new Exception("Other thread"); }).Start();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
    
                string a = null;
                a.PadLeft(10);
            }

    随便点击一个按钮都能触发异常处理,生成如下dump.dmp文件

    拖到visual studio里面打开如下

     

    “使用 仅托管进行调试”以下是打开dump文件后的效果,直接定位到异常处:

     

    最近比较忙,时间紧张,文章写得比较粗糙,大家应该能明白什么意思了,有疑问欢迎留言。

    参考:

    AppDomain.CurrentDomain.UnhandledException not firing without debugging

    Writing MiniDumps in C#

    application level global exception handler didn't get hit

    How to create minidump of a .NET process when a certain first chance exception occurs

     Should use both AppDomain.UnhandledException and Application.DispatcherUnhandledException?

     The simplest way to generate minidump for mixed managed & unmanaged stack?

    CLRDUMP

    How to Use the Debug Diagnostic Tool v1.1 (DebugDiag) to Debug User Mode Processes

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 07:17 , Processed in 0.078757 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表