3

我有一个大型 Compact Frameworks V2.0 应用程序,在大多数情况下运行良好。在某些设备上大约每天一次,用户会收到一个本机错误 0xC0000005,该错误未被标准托管的 Try/Catch 块捕获。

我的应用程序以固定的时间间隔通过 ASMX 调用与服务器同步。该问题似乎发生在同步期间。除了同步时发生的 ASMX 调用外,还有相当多的业务逻辑,但其中 98% 是托管代码。我已经查看了我所有的 P/Invokes 和应用程序原生 C++ 库,此时我大约 95% 确定这不是问题所在。

由于这只发生在某些设备上并且很少发生(每天少于一次),因此很难隔离。我已经分析了我的代码,它看起来好像发生在应用程序中的随机位置,所以我怀疑某些东西正在破坏内存。

任何有关如何进一步解决此问题的想法将不胜感激。

4

2 回答 2

5

0xC0000005 是访问冲突,因此某些东西正试图读取或写入它无权访问的地址。这些往往很难找到,经验是最好的工具之一(好吧,Platform Builder 的调试器也很有帮助,但这是一个完全独立的调试途径,需要你可能没有或已经有的经验试过了)。我发现日志记录往往不如减法编码有用 - 尽可能使用模拟托管调用删除 P/invoke 调用。

托管应用程序中的访问冲突通常由于以下原因之一发生:

  • 您 P/Invoke 将句柄传递给托管对象的本机 API,并且本机 API 使用该句柄。如果在本机 API 运行时获得集合和压缩,则托管对象可能会移动并且指针变得无效。
  • 您 P/Invoke 的缓冲区太小或小于您传入的大小,并且 API 超出了读取或写入
  • 传递给 P/Invoke 调用的指针(IntPtr 等)无效(-1 或 0),并且本机在使用前未对其进行检查
  • 您 P/Invoke 本机调用并且本机代码耗尽内存(通常是虚拟的)并且不检查失败的分配和读取/写入无效地址
  • 您使用未初始化的 GCHandle 或以某种方式指向已完成并收集的对象(因此它不是指向对象,而是指向对象曾经所在的地址)
  • 您的应用使用句柄来处理因睡眠/唤醒而无效的内容。这更深奥,但肯定会发生。例如,如果您在存储卡上运行应用程序,则整个应用程序不会加载到 RAM 中。使用中的部分被按需调入执行。这一切都很好。现在,如果您关闭设备电源,驱动程序将全部关闭。当您重新启动电源时,许多设备只需重新安装存储设备即可。当您的应用程序需要在更多程序中请求页面时,它不再是它原来的位置并且它死了。安装存储上的数据库可能会发生类似的行为。如果您有数据库的打开句柄,则在睡眠/唤醒周期后,连接句柄可能不再有效。

You'll note the trend here that almost all of these are P/Invokes and that's no accident. It's quite difficult to get managed code to do this on its own.

于 2008-12-31T14:51:38.517 回答
1

My native C++ exception handling was not including async exception, and thus was not catching access violation exceptions.

This may/may not be helpful for my problem, but might be helpful for others.

Using the /EHa switch as documented in this link will allow for catching these types of exceptions:

http://msdn.microsoft.com/en-us/library/1deeycx5.aspx

于 2008-12-31T19:09:06.390 回答