分类 调试 下的文章

当.NET程序有未处理的异常时,您可能会希望关闭出现的调试对话框。下面有两个选项:

1、启用JIT调试的注册表项

对于包含托管代码的应用程序,公共语言运行库将显示类似于JIT附加调试器的对话框。控制此选项的注册表项称为HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\DbgJITDebugLaunchSetting。

  • 如果值为0,则通过消息框提示用户。选择包括:“继续”---这将导致堆栈转储和进程终止。“附加调试器”---在这种情况下,运行时生成DbgManagedDebugger注册表项中列出的调试器。如果没有,则返回控件并终止进程。
  • 如果值为1,则返回控件。这会导致堆栈转储,然后终止进程。(不再有对话)
  • 如果值为2,则生成DbgManagedDebugger注册表项中列出的调试器。

2、如果要禁用“JIT调试”对话框,但仍需要错误对话框

Visual Studio.NET|Tools|Options|Debugging|Just-In-Time 下取消“"Common Language Runtime"”的选择,现在将显示“确定/取消”对话框,而不是“选择调试器”对话框。注意:上面选项1中的注册表项需要为0才能显示对话框。

在某些情况下,我们会执行实时调试以确定服务器故障的根本原因。在内存转储的情况下,文件通常非常大,因此通过网络复制文件,即使是在最快的广域网连接上,也可能需要很长时间。解决方案是远程调试。

你应该怎么做?

首先,需要两个人:一个是远程人员,另一个是通过使用安装在他们机器上的调试器调试进程来帮助远程用户的专家。
假设你是帮助远程人的专家。流程如下:
1、远程用户使用windbg打开转储文件、调试进程或内核调试远程位置的计算机。
2、远方的人决定,“我需要帮助!”
3、远程用户只在windbg提示符下需输入..server tcp:port=9999。

 

注意下面的输出。
服务器已启动。客户机可以使用这些命令行中的任何一个进行连接

0: <debugger> -remote tcp:Port=9999,Server=MyServerName

样例工程

在VS2013里新建一个C#控制台工程,写下如下代码:

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading;namespaceConsoleApplication1
{
classProgram
{
static void Main(string[] args)
{
Thread t1
= new Thread(newThreadStart(TestMethod));
t1.Start();
t1.Join();
}
public static voidTestMethod()
{
while (true)
{
StringBuilder sb
= new StringBuilder(1024*1024);
Thread.Sleep(
0);
}
}
}

}

在某些情况下,您可能希望使用用户模式调试器从内核调试器中调试进程。它可能是你有一个加载内核模式驱动程序的应用程序,并且你希望能够调试应用程序的用户模式方面,然后进入内核以跟踪对内核的调用。

这是你需要做的!

通过串行电缆(调制解调器电缆)、USB电缆或FireWire电缆连接内核调试器,并将您的计算机配置为内核调试。要在Vista或Windows 2008上启用调试选项,必须使用bcdedit.exe文件因为那些操作系统不再使用启动.ini文件。下面是一个例子:

bcdedit /debug {<guid>} <ON | OFF>bcdedit/dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200

简介

EXCEPTION_HIJACK,值为0xe0434f4e。意思是CLR线程劫持异常。异常劫持是CLR在挂起线程进行垃圾收集的过程中抛出的。它的抛出是为了帮助停止后恢复执行。它定义在..\clr\src\inc\corexcep.h头文件里,如下:

#define EXCEPTION_HIJACK  0xe0434f4e    // 0xe0000000 | 'COM'+1

详细说明

在现实开发中,经常会出现多个线程同时访问托管堆的情况,或至少会有多个线程同时操作堆中的对象。一个线程引发垃圾回收时,其它线程绝对不能访问任何线程,因为垃圾回收器可能移动这些对象,更改它们的内存位置。CLR想要进行垃圾回收时,会立即挂起执行托管代码中的所有线程,正在执行非托管代码的线程不会挂起。然后,CLR检查每个线程的指令指针,判断线程指向到哪里。接着,指令指针与JIT生成的表进行比较,判断线程正在执行什么代码。

如果线程的指令指针恰好在一个表中标记好的偏移位置,就说明该线程抵达了一个安全点。线程可在安全点安全地挂起,直至垃圾回收结束。如果线程指令指针不在表中标记的偏移位置,则表明该线程不在安全点,CLR也就不会开始垃圾回收。在这种情况下,CLR就会劫持该线程。也就是说,CLR会修改该线程栈,使该线程指向一个CLR内部的一个特殊函数。然后,线程恢复执行。当前的方法执行完后,他就会执行这个特殊函数,这个特殊函数会将该线程安全地挂起。然而,线程有时长时间执行当前所在方法。所以,当线程恢复执行后,大约有250毫秒的时间尝试劫持线程。过了这个时间,CLR会再次挂起线程,并检查该线程的指令指针。如果线程已抵达一个安全点,垃圾回收就可以开始了。但是,如果线程还没有抵达一个安全点,CLR就检查是否调用了另一个方法。如果是,CLR再一次修改线程栈,以便从最近执行的一个方法返回之后劫持线程。然后,CLR恢复线程,进行下一次劫持尝试。所有线程都抵达安全点或被劫持之后,垃圾回收才能使用。垃圾回收完之后,所有线程都会恢复,应用程序继续运行,被劫持的线程返回最初调用它们的方法。

异常结构填充

ExceptionAddress: 762819b2 (KERNELBASE!RaiseException+0x00000062)
ExceptionCode: e0434f4e//异常代码
ExceptionFlags: 00000000
NumberParameters: 0//没有附加参数信息