【问题标题】:Application crashes says : Access violation reading location应用程序崩溃说:访问冲突读取位置
【发布时间】:2009-06-10 08:13:20
【问题描述】:

我的应用程序在运行大约 18 小时后崩溃。我无法调试代码中实际崩溃的点。我检查了调用堆栈——它没有提供任何这样的信息。调用堆栈中的最后几个调用是灰色的——意味着我看不到那部分的代码——它们都属于 MFC 库。

但是,当它崩溃时,我会弹出这个“MicroSoft Visual Studio”,上面写着:

NIMCAsst.exe 中 0x7c809e8a 处未处理的异常:0xC0000005: 访问冲突读取位置 0x154c6000。

以上信息对了解崩溃的位置是否有用。是否有任何软件可以告诉我代码中的哪个变量保存了特定的内存地址。

【问题讨论】:

  • 它只是在某个随机点崩溃。它进入 MFC dll 并在那里崩溃,调用堆栈没有说明我的代码中的哪个点在那里控制了。
  • 如果您连接了调试器,您应该能够清楚地看到您的哪一行代码调用了 MFC。如果不是,则可能是启用了优化,或者您的 .pdb 文件与可执行文件不同步。
  • 你好@RakeshAgarwal,我在 VS 2005 中的 c++ 项目中遇到了同样的错误。我只想知道你是如何修复这个错误的。如果您能与我分享您的方法,那将非常有帮助。

标签: c++ visual-studio mfc


【解决方案1】:

如果您有时无法捕捉到异常,您只需要逐行检查您的代码,这非常令人不快,但我会花钱买它,因为您的代码不在 MFC 中(总是有我的错误)。仔细检查您是如何使用内存的,以及您传递给 MFC 函数的内容。

【讨论】:

    【解决方案2】:

    崩溃可能是由缓冲区溢出或其他类型的内存损坏引起的。这已经覆盖了包含返回地址的堆栈的某些部分,这使得调试器无法正确重建堆栈跟踪。或者,导致崩溃的代码,您没有正确的符号(如果堆栈跟踪显示模块名称,就是这种情况)。

    我的第一个猜测是检查调用崩溃代码的代码是否可能导致崩溃。在崩溃之前,您是否遇到任何其他异常或错误情况?也许您忽略了错误返回?您是否尝试过使用Debug Heapadplus 呢? Application verifier 开启堆检查?

    其他可能性包括在代码上运行像 pclint 这样的工具来检查内存使用的明显问题。你在使用线程吗?也许有一个竞争条件。这个列表真的可以永远持续下去。

    【讨论】:

    • 这个错误可能即将到来-但是发生崩溃的时间并不一致-运行6小时后随时崩溃。所以,我不能监视这么长时间返回的错误.
    【解决方案3】:

    以上信息只告诉你哪些内存被非法访问了。

    您可以使用异常处理来缩小问题发生的范围,但您至少需要知道要寻找哪个角落。

    您说您正在查看调用堆栈,这表明您正在使用调试器。 MFC 的源代码是可用的(但可能不是所有的 vc++ 版本),所以原则上可以通过它进行跟踪。您使用的是哪个 VC++ 版本?

    该错误需要很长时间才能发生的事实表明它是内存损坏。其他一些函数写入它不拥有的位置。这工作了很长时间,但最终该函数更改了 MCF 需要的指针,并且在一段时间后 MFC 访问了该指针并通知您。

    有时,“位置”可以被识别为数据,在这种情况下,您会有提示。 F.e.如果错误说:

    访问冲突读取位置0x31323334

    您会将此识别为 ASCII 字符串“1234”的一部分,这可能会导致您成为罪魁祸首。

    【讨论】:

    • 我正在使用 Visual Studio 2005,并且我已将应用程序与调试解决方案附加在一起。
    【解决方案4】:

    正如 Patrick 所说,几乎可以肯定是您的代码提供了 MFC 无效值。一种猜测是您传递的长度不正确,因此图书馆的阅读量太大了。但确实有很多可能的原因。

    【讨论】:

    • 用户代码不仅可以提供一些结构不正确的数据,而且它可以例如调用一个在完成时调用回调的函数,并给它一个指向有效对象的用户数据指针,但此时该对象被删除回调到达。这里的可能性是无穷无尽的。
    【解决方案5】:

    崩溃是否可以清楚地重现?

    如果是,请使用日志文件!您应该使用日志文件并添加仅记录传递的源文件/行号的数字语句。从入口点(主事件处理程序)和最常见的执行路径处的一些语句开始。崩溃后检查日志文件中的最后一个条目。然后在必须通过的路径/路径下添加新条目等。通常在这项工作的几次迭代之后,您会发现故障点。如果您的等待时间过长,日志文件可能会变得很大,并且每次迭代将需要另外 18 小时。您可能需要添加一些旋转日志文件等技术。但是通过这种技术,我能够找到一些类似的错误。

    还有一些问题:

    您的应用程序是多线程的吗?

    它是否使用任何不受 stl 或类似容器管理的数组(是否使用 C-Strings、C/C++-Arrays 等)?

    【讨论】:

    • 是的,应用程序是多线程的。没有不由 stl 管理的数组。日志记录是个好主意。
    • 另外,当附加到日志文件时,我建议每次都打开、写入、刷新和关闭日志文件,以便在发生崩溃时正确关闭日志文件,其中包含最后打印的文本。
    【解决方案6】:

    尝试将调试器附加到进程并让调试器在访问冲突时中断。

    如果这不可能,那么我们使用一个名为“用户模式进程转储器”的工具在发生访问冲突的地方创建进程的内存转储。你可以在这里找到下载:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=E089CA41-6A87-40C8-BF69-28AC08570B7E&displaylang=en

    工作原理:您可以在每个进程(或可选的系统范围)的基础上配置规则,并让该工具在检测到异常列表中的任何一个时创建小型转储或完整转储 -其中之一是访问冲突。转储完成后,应用程序将继续正常运行(因此,如果未处理访问冲突,您将看到此对话框)。

    请注意,您的进程中的所有访问违规都会被捕获 - 即使是那些随后会被处理的违规,完整转储也可能会根据应用程序使用的内存量创建一段时间(一个进程需要 10-20 秒)消耗 100-200 MB 的私有内存)。因此,在系统范围内启用它可能不是一个好主意。

    然后,您应该能够使用 WinDbg (http://www.microsoft.com/whdc/devtools/debugging/default.mspx) 等工具分析转储以找出发生了什么 - 在大多数情况下,您会发现您只需要一个小型转储,而不是一个完整转储(但是如果您的应用程序不需要使用大量内存,那么除了转储的大小和创建转储所需的时间之外,完整转储并没有很多缺点)。

    最后,请注意,使用 WinDbg 调试访问冲突可能是一个相当复杂和复杂的过程 - 如果您可以通过另一种方式获取堆栈跟踪,那么您可能想先尝试一下。

    【讨论】:

      【解决方案7】:

      这可能是内存泄漏的原因,有各种博客可以教检查应用程序中的内存泄漏,您只需从 Windows 任务管理器中观察进程的物理内存,您可以在某个阶段发现内存保持增加并耗尽内存。您还可以尝试使用 windbg 工具来识别代码中的内存泄漏。我没有使用过这个工具,只是对此有所了解。

      【讨论】:

        【解决方案8】:

        这个问题很老了,我也遇到过同样的问题, 但我很快就解决了 - 都是关于线程的:

        首先,请注意更新GUI只能在主线程中完成。

        我的问题是我试图从 Worker 线程(而不是 主线程)处理 GUI,但我遇到了同样的错误:0xC0000005。 我通过发布一条消息(在主线程中执行)解决了这个问题 - 问题已经解决了:

        typedef enum {
          WM_UPDATE_GUI
        }WM_MY_MSG
        
        // register function callback to a message
        BEGIN_MESSAGE_MAP(CMyDlg, CDlgBase)
          ON_MESSAGE(WM_UPDATE_GUI, OnUpdateGui)
        END_MESSAGE_MAP()
        
        // For this example - function that is not invoked in the Main Thread:
        void CMyDlg::OnTimer() 
        { 
          CString str_to_GUI("send me to gui"); // send string to gui
          // Update_GUI(str_to_GUI); // crashed
          ::PostMessage(hWnd, MyMsg::WM_UPDATE_GUI, (WPARAM)&str_to_GUI, 0);
        }
        
        HRESULT CMyDlg::OnUpdateGui(WPARAM wParam, LPARAM lParam)
        {
          CString str = *(CString*)wParam; // get the string from the posted message
          Update_GUI(str);
          return S_OK;
        }
        

        【讨论】:

          猜你喜欢
          • 2014-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-31
          • 2016-05-28
          • 2017-01-09
          • 2014-11-09
          相关资源
          最近更新 更多