代码之家  ›  专栏  ›  技术社区  ›  dyp

C++/Windows:如何报告内存不足(BADYOLLYC)?

  •  8
  • dyp  · 技术社区  · 14 年前

    我目前正在为WindowsMSVC++(9.0)应用程序(即异常结构和类型/继承、调用堆栈、错误报告和日志记录等)开发基于异常的错误报告系统。

    我现在的问题是:如何正确报告;记录内存不足错误?

    发生此错误时,例如 bad_alloc 被人扔了 new 哦,可能有许多“功能”不可用,主要是关于进一步的内存分配。通常,如果异常被抛出lib中,我会将其传递给应用程序,然后使用消息框和错误日志文件来报告和记录它。另一种方法(主要针对服务)是使用Windows事件日志。
    我的主要问题是要汇编一个错误消息。 为了提供一些错误信息,我想定义一个静态错误消息(可以是字符串文本,最好是消息文件中的条目,然后使用FormatMessage),并包含一些运行时信息,比如调用堆栈。
    此用途所需的函数/方法

    • STL公司( std::string, std::stringstream, std::ofstream )
    • 阴极射线管( swprintf_s, fwrite )
    • 或Win32 API( StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile )



    为了证明可能有问题,我写了一个很小的应用程序,引发了一个不好的问题:

    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;
    }
    


    请考虑可能有多个进程[edit]和多个线程[/edit]消耗大量内存,因此释放预先分配的堆空间不是一个安全的解决方案,以避免要报告错误的进程的内存环境不足。

    提前谢谢!

    4 回复  |  直到 14 年前
        1
  •  2
  •   peterchen    14 年前
    • 预先分配所需的缓冲区
    • 使用MessageBox(MB|SYSTEMMODAL | MB|OK)MSDN提到了报告OOM条件的方法(一些MS blogger将此行为描述为预期的:MessageBox不会分配内存)

    日志记录比较困难,至少日志文件需要已经打开。

    可能最好是 FILE_FLAG_NO_BUFFERING FILE_FLAG_WRITE_THROUGH ,以避免任何缓冲尝试。第一个要求写操作和内存缓冲区是扇区对齐的(即,您需要查询GetDiskFreeSpace,按此对齐缓冲区,并且只写到“扇区大小的倍数”文件偏移量,并且是扇区大小的倍数。我不确定这是必要的,还是有帮助的,但是一个全系统的OOM在哪里 分配失败是很难模拟的。

        2
  •  3
  •   Alex F    14 年前

    “正在释放预先分配的堆空间…”。这正是我在读你的问题时所想的。但我想你可以试试。每个进程都有自己的虚拟内存空间。由于另一个进程占用大量内存,如果整个计算机都在工作,这一点可能仍然有效。

        3
  •  1
  •   TheUndeadFish    14 年前

    在Windows(和其他现代操作系统)下,每个进程都有自己的地址空间(又称内存),与其他运行的进程分开。所有这些都与机器中的文字RAM是分开的。操作系统已经虚拟化了远离物理RAM的进程地址空间。

    这就是Windows如何将进程使用的内存推送到硬盘上的页面文件中,而这些进程不知道发生了什么。

    这也是单个进程如何分配比机器有物理RAM且仍在运行的内存更多的内存。例如,在内存为512MB的机器上运行的程序仍然可以分配1GB的内存。Windows不能同时将所有的内容都保存在RAM中,有些内容会保存在页面文件中。但程序不知道。

    因此,如果一个进程分配内存,它不会导致另一个进程的内存减少。每个过程都是独立的。

    每个过程只需要担心自己。所以释放预先分配的内存块的想法实际上是非常可行的。

        4
  •  0
  •   Ana Betts    14 年前

    不能使用CRT或MessageBox函数来处理OOM,因为它们可能需要内存,如您所述。唯一真正安全的方法是在启动时分配一块内存,您可以将信息写入并打开文件或管道的句柄,然后在退出时向其写入文件。