部分崩溃的应用程序?如何捕获无法捕获的异常?

时间:2010-07-27 07:34:34

标签: c# compact-framework windows-ce

我有一个用C#编写的程序,在Windows CE设备上运行(在Compact Framework上)。它处理最少的用户操作(按钮点击),使用串行端口和TCP / IP通信。

问题是软件有时会自行关闭。 在后台,应用程序(或应用程序的某些部分)似乎仍在运行(至少在一个记录的情况下),因为它使用串行端口,因此重新启动应用程序没有帮助。我不能重现这个问题,因为它发生在大多数情况下,当没有用户交互,没有串口通信和网络通信都是“我还活着”的消息时,软件看似没有理由崩溃。 (我尝试在调试模式下实现它至少知道代码中的问题在哪里,如果它是一个软件错误,但到目前为止我没有运气。)

由于我的想法已经不多了,问题是:什么错误或异常或操作系统操作或硬件故障会导致这种行为?

在同一类型的不同设备上已经出现问题,因此它不应该是硬件错误。 (或者我的所有硬件都有相同的错误。)处理异常,所以它不应该是一个例外。处理未处理的异常也是如此,因此它也不应该是未处理的异常。 (我的猜测是它是由StackoverflowException引起的,因为我不知道任何其他无法捕获的异常,但代码中没有递归,至少不是自愿的,所以它不应该'也是一种可能性。)

3 个答案:

答案 0 :(得分:10)

有些异常无法捕获,这些异常与.NET版本不同。并且可以捕获并记录一些异常,但无法从(内存异常)中恢复。但是,可以调试它们(这些被称为first chance exceptions,第一次机会总是用于调试器,第二次机会是代码,感谢JeroenH指出这一点)。这是一个post at CodeProject that explains this原则。

您应该做的是在Visual Studio中选择您怀疑可能发生的一些候选异常,并将调试器附加到正在运行的实例。

拥有非托管资源(串口)意味着您可以拥有非托管泄漏(未正确使用IDisposable + using)和非托管异常。这些异常只能在try / catch块中使用空catch(即,不指定偶数Exception非托管异常的父项)来捕获。

PS:在finally块或终结器/析构函数中引发异常时,可能会发生一些未定义的行为。此外,没有多少异常通过线程边界传播并终止所有线程。

修改

为了使事情更清楚一些,CLR(及其规范)定义为不可捕获的例外情况。基本上,这些都是跨越线程边界的异常。这些异步异常在锁定内发生时将导致状态损坏。众所周知的是OutOfMemoryExceptionThreadAbortExceptionStackOverflowException。当同步代码中出现OutOfMemoryExceptionStackOverflowException时,您不太可能纠正状态,CLR将终止您的应用程序。

此外还有ExecutionEngineExceptionBadImageFormatException,它们不应该在可验证的代码中发生,不应该被捕获。 TypeLoadExceptionMissingMemberException之类的例外有时会被捕获,有时候不会被捕获(如果缺少链接的程序集,那么很难捕捉这些,你不应该这样,但是如果你使用反射,你应该抓住这些)。

简而言之:异常应该在它们发生的线程中捕获。如果它们发生在另一个线程中,你将无法捕获异常,因为它们不会被传播(ThreadAbortException除外)。您的应用程序在异常后保持活动状态(至少,您认为),因此可以合理地假设异常不会发生在您尝试捕获它的线程中。使用Debug>例外窗口,您可以选择任何异常并在代码发生时中断。

关于例外的说明

关于托管和非托管异常的补充说明。您无法使用catch (Exception e)捕获非托管异常,因为非托管异常不会从Exception继承。相反,使用空catch,它将为您捕获任何非托管异常。围绕您的应用程序和线程入口点方法进行包装,您应该能够捕获大多数可捕获的异常。

答案 1 :(得分:3)

您可能有本机异常或访问冲突(通常会显示为第一次机会异常)。没有任何托管异常处理可以捕获其中一个 - 关键是不首先导致异常。

您是否正在调用或拨打不安全的电话?如果您正在调用API并导致类似缓冲区溢出或堆栈损坏,您会看到这种行为(尽管通常会让操作系统对话框抱怨。

追踪这些往往很难。这是一个CE设备 - 它有一个调试端口(它通常是一个串口)?异常很可能会在那里转储消息,因此如果您有权访问消息,那么这是一个很好的起点。如果您有KITL,那么在应用程序运行时在调试中运行操作系统也可能会捕获正在发生的任何事情。

答案 2 :(得分:2)

如果使用Thread类启动辅助线程,并且未指定它们是后台线程,则它们将使进程保持运行直到它们退出,即使主线程已完成(即主窗体已关闭,并且主要线程已完成)方法已经返回。)

如果你有一个StackOverflowException,你的进程将被Windows彻底杀死,所以不是这样。