【问题标题】:What are some techniques for troubleshooting very intermittent Access Violation on a Windows Mobile Device?有哪些技术可以解决 Windows Mobile 设备上非常间歇性的访问冲突?
【发布时间】:2010-09-29 00:18:09
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你能说服崩溃发生在设备模拟器中吗?通过模拟器进行本机调试可能会让您有所收获;除此之外,您所能使用的只是拔掉应用程序的大部分内容并查看它是否停止死亡。换句话说,一点也不好玩。
  • Tnx...不是真的...我无法“说服”它以任何方式崩溃...我认为它可能与即将到来有关即使在设置电源要求后也退出睡眠模式。设备充电时我从未见过问题。
  • 是的,睡眠/唤醒是完全不同的事情。我已经修改了我的答案以包括这一点。

标签: windows-mobile compact-framework access-violation


【解决方案1】:

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

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

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

您会注意到这里的趋势是,几乎所有这些都是 P/Invokes,这绝非偶然。让托管代码自行执行此操作非常困难。

【讨论】:

  • 感谢 ctacke 的彻底反馈 - 经过彻底的代码审查后,我看到的唯一属于上述类别之一的是 StringBuilder,在将其发送到 P/Invoke 之前我没有固定。我在某处读到编组以某种方式处理该问题,您知道这是否正确吗?
  • 我只是想尝试减码方法,但是两次失败之间至少要间隔一天,这可能会很困难。似乎它只发生在某些设备上,当它处于睡眠模式/唤醒同步时不充电。这可能是 BSP 或紧凑框架原生代码中的内容吗?
  • 在 Windows CE 中,您可以永远假设平台不应受到指责。这肯定是一个问题。至于 StringBuilder,它取决于使用情况。如果是同步调用,你是安全的。如果它是异步的,不是,你不是。
  • 再次感谢您提供更多详细信息,它在同步调用中,所以我想我很安全。崩溃报告中的详细信息有三个值,ExceptionCode 是 0xC00 ExceptionAddr:0x12341234 和 Reading:0x0000000 我假设读取 0x00 可能是内存分配失败
  • 而 0x[OTHERADDR] 用于读取意味着托管对象可能已移动或某些内容已损坏。正确的?事实上,关于 DLL 映像的 ExceptionAddress 值有什么意义吗?再次感谢您的帮助,这让我很难过。
【解决方案2】:

我的原生 C++ 异常处理不包括异步异常,因此没有捕获访问冲突异常。

这可能/可能不会对我的问题有帮助,但可能对其他人有帮助。

使用此链接中记录的 /EHa 开关将允许捕获这些类型的异常:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    相关资源
    最近更新 更多