应用程序崩溃说:访问违规读取位置

时间:2009-06-10 08:13:21

标签: c++ visual-studio mfc

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

然而,当它崩溃时,我得到这个'MicroSoft Visual Studio'弹出窗口,其中说:

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

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

8 个答案:

答案 0 :(得分:5)

如果你不能抓住异常有时你只需要逐行检查你的代码,非常不愉快,但我会把钱作为你的代码而不是MFC(总是带着我的错误)。检查你如何使用内存以及你要仔细传递给MFC功能的内容。

答案 1 :(得分:2)

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

我的第一个猜测是检查代码,该代码调用可能导致问题的可能问题而崩溃的代码。在崩溃之前你有任何其他异常或错误条件吗?也许你忽略了一个错误回报?您尝试使用Debug Heap了吗?那么adplus呢? Application verifier打开堆检查?

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

答案 2 :(得分:1)

以上信息仅告诉您非法访问了哪些内存。

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

你说你正在看到调用堆栈,这表明你正在使用调试器。 MFC的源代码是可用的(但可能不适用于所有vc ++版本),因此原则上可以追溯它。您使用的是哪个VC ++版本?

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

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

访问冲突读取位置0x31323334

你会认识到这是ASCII字符串“1234”的一部分,这可能会导致你成为罪魁祸首。

答案 3 :(得分:1)

帕特里克说,这几乎肯定是你的代码给MFC无效的值。一个猜测是你传递的长度不正确,所以图书馆读得太远了。但实际上有很多可能的原因。

答案 4 :(得分:1)

碰撞是否清晰可重复?

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

还有一些问题:

您的应用是多线程的吗?

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

答案 5 :(得分:0)

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

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

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调试访问冲突可能是一个相当复杂的过程 - 如果您可以通过另一种方式获得堆栈跟踪,那么您可能需要先尝试。

答案 6 :(得分:0)

这是可能的内存泄漏的原因,有各种各样的博客可以教授检查应用程序中的内存泄漏,你只需从Windows任务管理器对进程的物理内存进行观察,你可以在内存保持的某个阶段找到增加&内存耗尽。您还可以尝试使用windbg工具来识别代码中的内存泄漏。我没有使用过这个工具,只是对此提出了一些看法。

答案 7 :(得分:0)

这个问题已经很老了,我也遇到了同样的问题, 但我很快解决了它-这与线程有关:

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

我的问题是我试图通过 Worker Thread (而不是 Main Thread )来处理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;
}