【问题标题】:AccessViolationException in Release mode (C++)发布模式下的 AccessViolationException (C++)
【发布时间】:2009-08-28 01:14:46
【问题描述】:

当我从 Visual C++ 以发布模式运行我的应用程序时,出现以下异常。

未处理的异常: System.AccessViolationException: 试图读或写保护 记忆。这通常是一个迹象 其他内存已损坏。在 _cexit() at .LanguageSupport._UninitializeDefaultDomain(Void * cookie) 在 .LanguageSupport.UninitializeDefaultDomain() 在 .LanguageSupport.DomainUnload(对象 来源,Eve ntArgs 论点)在 .ModuleUninitializer.SingletonDomainUnload(对象 t 源,EventArgs 参数)

这在调试模式下不会发生。最初,我在家用计算机上看到了这个异常,但在工作计算机上却没有。当我继续在我的工作计算机上开发时,我最终碰到了它。

另外,我发现当我添加三个 const std::string 变量时,抛出了异常。如果我删除了,那么一切都很顺利。

另一条信息:我发现在发布模式下关闭所有编译器优化会使异常消失

发生了一些可疑的事情。有关如何追踪此问题的任何想法?

感谢您的帮助, 乔

【问题讨论】:

  • 看起来像缓冲区溢出或指针坏了。在这些情况下,错误可能就在抛出异常之前的某个地方......如果你幸运的话。调试愉快。

标签: memory managed-c++ access-violation


【解决方案1】:

乔,你有一个memory leak

您可能正在尝试使用一些已删除的内存。

请参阅this article 了解内存泄漏的常见原因以及如何识别它们,否则,搜索“C++ 内存分析器”+您的编译器/平台,它将提供适合您的编译器和平台的内存分析器的链接,这些将通过观察程序在运行时如何使用内存来帮助追踪内存泄漏。

希望这会有所帮助。

编辑

如何追踪它?这不是我的想法,在其他地方可能有更好的建议。 . .

查找代码崩溃的地方,它会在访问某个指针的内容(或删除指针)时发生。 问题是该指针要么 a) 从未被分配 b) 已被删除。 遍历对该类型指针的所有引用,它们是否用于复制 ctors/赋值运算符?

如果是这样,是复制的内容还是只是指针? 如果只是指针,那么包含类是否试图删除指针?如果是这样,第一个死掉的类会成功,第二个会抛出访问冲突。

如果您没有显式编码复制 ctor 和 operator=,那么您应该隐藏它们(声明私有原型但不实现它们),这会阻止编译器为您生成默认实现。

当您隐藏它们时,在使用它们的任何地方都会出现编译器错误,可能是您可以清理它们,或者您需要为每个类实现复制 ctor 和 operator=。

我从明天或两周开始休假,如果您对此有任何疑问,请立即给我发电子邮件(点击我的 SO 用户页面上的链接)。

【讨论】:

  • 谢谢。我觉得你是对的。我们在泄漏方面遇到了很多问题(我想这是课程的标准)。我们正在使用 MS 内存泄漏工具:_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetBreakAlloc(665); _CrtMemState 状态; _CrtMemCheckpoint(&state);关于如何追踪这一点的任何想法?
【解决方案2】:

您是否有任何代码被#defined 用于在您的代码中进行调试?

#ifndef _DEBUG
   //release only code such as liscensing code
#endif

这是可能导致问题的一件事,我以前也遇到过。

另一种可能性是 VS 问题(或您使用的任何 IDE)。 尝试直接运行release .exe,而不是通过开发环境,看看是否还有同样的问题。

【讨论】:

  • 我会调查的。谢谢。
  • 直接运行.exe还是崩溃吗?
  • 我直接运行了.exe,还是抛出异常。
【解决方案3】:

可以这么说,自从我“愤怒地”完成 C++ 以来已经有一段时间了,所以我在下面所说的部分(或实际上全部)可能已经过时了。

您是否使用托管 C++?如果不是,那么它听起来像一个未初始化的指针。过去的情况是,所有指针在调试中都为空,我记得关于关闭此行为的一些事情,但我现在不记得完整的细节。

字符串是否超出了它们的变量?不太可能使用 std::string,但值得消除。

【讨论】:

  • 我没有使用 CLR,所以我猜代码不是托管的,对吧?有趣的是,我减小了用于初始化 const std::string 变量的字符串的大小,并看到异常消失了。这是否意味着字符串超出了它的变量?谢谢。
  • 正如我所说,自从我完成 C++ 并且从未使用托管代码以来已经有一段时间了,但是如果您不使用 CLR,那么我猜您的代码不是托管的。如果更改字符串会改变行为,则表明这就是问题所在,但实际上坐下来调试代码总是很难确定。
  • 托管代码会停止缓冲区溢出吗?我认为主要的好处是垃圾收集,但我不是专家。
  • @David 我认为它不会阻止缓冲区溢出。我更多地考虑内存管理和未初始化的指针。
【解决方案4】:

几种可能性:

我猜你正在读/写超过本地数组结束。在调试版本中,这可能会起作用,因为内存分配不紧密。在发布版本中,这更有可能导致问题,具体取决于数组旁边分配的内容。

另一种可能性是您在某处有一个未初始化的指针。 VC 默认在调试模式下初始化局部变量,而不是在发布模式下。因此代码如下:

int* p;
if (p != NULL) { /* do something */ }

在发布模式下通常会失败。

【讨论】:

  • 非常感谢。对我来说,第一种可能性似乎比第二种可能性更大。我这样说是因为我可以通过更改某些字符串的大小来摆脱异常。如果是指针初始化问题,那我应该还是会看到异常吧?
  • @Joe - 如果它是一个初始化指针,你不会在调试中看到它,因为@eidolon 和我都指出默认情况下 VC 在调试模式下初始化局部变量。
  • 对。我可以通过在 Release 模式下更改字符串大小来消除异常。
【解决方案5】:

错误消息强烈表明您存在内存问题,可能会覆盖内存。这些很难找到,但您可以通过谷歌搜索“visual c++ memory corruption tool”找到一些可能的解决方案。

内存损坏的问题在于它是不可预测的。它不一定有任何后果,如果有,它们可能不会导致崩溃。这样的崩溃很好,因为它告诉你你遇到了问题。

摆弄调试与发布、添加或删除部分代码、更改优化选项等不太可能解决问题。即使是这样,如果进行任何更改,它也可能会突然出现。

所以,您遇到了内存损坏问题。这些几乎总是很难找到,但有工具。你需要解决这个问题。

您还可以查看您的商店做法。您是否使用不太安全的构造(例如new 数组而不是vector<>)?您是否有编码标准来尝试降低风险?你有代码审查吗?内存损坏可能是阴险的和破坏性的,您希望尽可能避免它。

【讨论】:

    【解决方案6】:

    您得到的是来自操作系统的系统异常。这些没有被处理,因为它们不是 C++ 异常。但是,您可以将其转换为 C++ 异常并像普通异常一样捕获它们。

    这里有一篇很棒的文章 http://www.thunderguy.com/semicolon/2002/08/15/visual-c-exception-handling/(第 3 页),展示了如何创建一个 Windows 异常类,该类将使用 _set_se_translator 方法捕获异常并引发 C++ 异常。很棒的是您可以从 EXCEPTION_RECORD 结构中获取堆栈,尽管您必须添加该功能来处理该结构,但这将有助于缩小您对访问冲突的搜索范围。

    【讨论】:

      【解决方案7】:

      我认为这里的问题是未初始化的局部变量。 在调试模式下,变量通常会被初始化,并且不会出现任何异常。 但是在发布模式下可能会因此而出现错误。

      尝试查找访问可能导致异常的未初始化变量。

      假设你有布尔局部变量。

      bool bRet;
      

      在调试版本中,bRet 将被初始化为 0,您的代码运行良好。

      但在发布时它不会是 0 ,它会是一些随机值,并且您的代码可能会基于 bRet 执行某些操作。它可能稍后会导致异常,因为 bRet 值错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 2014-06-24
        • 1970-01-01
        相关资源
        最近更新 更多