【发布时间】:2011-04-01 19:08:16
【问题描述】:
我目前正在为 Windows MSVC++ (9.0) 应用程序开发基于异常的错误报告系统(即异常结构和类型/继承、调用堆栈、错误报告和日志记录等)。
我现在的问题是:如何正确报告和记录内存不足错误?
发生此错误时,例如作为new 操作抛出的bad_alloc,可能有许多“功能”不可用,主要涉及进一步的内存分配。通常,如果异常已被抛出到一个库中,我会将其传递给应用程序,然后使用消息框和错误日志文件来报告和记录它。另一种方法(主要用于服务)是使用 Windows 事件日志。
我遇到的主要问题是组合错误消息。
为了提供一些错误信息,我想定义一个静态错误消息(可能是字符串文字,最好是消息文件中的条目,然后使用 FormatMessage)并包含一些运行时信息,例如调用堆栈。
此用途所需的功能/方法要么
- STL (
std::string, std::stringstream, std::ofstream) - CRT (
swprintf_s, fwrite) - 或 Win32 API (
StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile)
除了在 MSDN 上记录之外,它们在 Windows 中都更多(Win32)或更少(STL)封闭源代码,所以我真的不知道它们在低内存问题下的行为。
为了证明可能有问题,我写了一个微不足道的小应用程序引发了 bad_alloc:
int main()
{
InitErrorReporter();
try
{
for(int i = 0; i < 0xFFFFFFFF; i++)
{
for(int j = 0; j < 0xFFFFFFFF; j++)
{
char* p = new char;
}
}
}catch(bad_alloc& e_b)
{
ReportError(e_b);
}
DeinitErrorReporter();
return 0;
}
运行了两个没有附加调试器的实例(在版本配置中,VS 2008),但“没有发生任何事情”,即我在错误报告中内部使用的 ReportEvent 或 WriteFile 中没有错误代码。然后,启动一个带调试器和一个不带调试器的实例,并让它们尝试通过在 ReportError 行上使用断点一个接一个地报告错误。对于附加了调试器的实例,这工作得很好(正确报告并记录了错误,即使使用 LocalAlloc 没有问题)!但是 taskman 表现出一种奇怪的行为,在应用程序退出之前释放了大量内存,我想是在抛出异常时。
请考虑可能有多个进程 [edit] 和多个线程 [/edit] 消耗大量内存,因此释放预分配的堆空间不是一个安全的解决方案,以避免要报告的进程的内存不足环境错误。
提前谢谢你!
【问题讨论】:
-
您是否考虑过提前保留一块内存,当系统进入内存不足的情况时,它将成为放置分配的来源?我只是为了优雅地退出应用程序而使用这种方法,但操作系统(OpenSolaris、Linux)会做类似的事情来给应用程序足够的时间来释放或换出低优先级分配并优雅地恢复。跨度>
-
目前,我使用一些堆栈空间(调用 InitErrorReporter 时声明的成员变量)为 CRT / WinSDK 函数提供缓冲区。但我不知道他们在内部做什么 - 请参阅 Alex Farber 的分析器。
-
很抱歉这条消息是骗人的——我想把它放在另一个问题上。
标签: c++ windows error-reporting out-of-memory