如何在禁用C ++异常(VS2010)的情况下确保内存不足的可靠性?

时间:2013-02-06 17:09:09

标签: c++ exception dll out-of-memory robustness

我正在开发一个性能关键的动态链接库(DLL),它也应该具有相对较小的二进制大小。由于它没有显式抛出任何异常,我想完全禁用异常支持。但是,有一个例外(双关语无意):当内存不足(OOM)时,我必须向应用程序报告错误代码,以便它有机会正常处理事情。代码库太大,无法单独检查每个分配并传播错误,并包含我不应该触及的外部代码。所以我想在DLL的导出函数中捕获OOM异常。

快速测试表明,在Visual C ++ 2010中禁用C ++异常时(即没有/ EHa,/ EHsc或/ EHs标志),在分配太多内存时,它仍会跳转到catch(std :: bad_alloc&)块。

所以它似乎按预期工作。但是,我收到以下1级警告:“C4530:使用了C ++异常处理程序,但未启用展开语义。指定/ EHsc”。 MSDN说“在帧中自动存储的对象,在执行throw的函数和捕获throw的函数之间,不会被破坏”。

究竟我会在这里失去什么?只要通过库创建的任何内容都可以删除,并且应用程序可以重新开始(如果它选择的话),可以将事物保留在未定义状态。是否有很大的泄漏记忆无法恢复的风险?

DLL是否使用单独的内存池?如果是这样,我可以清除它而不需要应用程序卸载DLL吗?我可以轻松地让我的库忽略任何进一步的(导出的)函数调用,直到应用程序执行重新初始化。

感谢您的建议。

1 个答案:

答案 0 :(得分:1)

一些预赛:

我不知道在未启用异常处理的情况下抛出异常是否是未定义的行为或不符合标准,但您肯定不会从堆栈中的对象获取堆栈展开/析构函数调用。

如果您使用RAII编写C ++样式代码用于互斥,文件,内存等,这是一个非常糟糕的事情。

继续,然后假设您的代码基本上是C风格的代码:

1)如果静态链接到C运行时库,则DLL不会与主应用程序共享堆。卸载DLL应该释放泄漏的内存 - 但同样要关心其他资源。

2)如果你动态链接到C运行时(很常见),那么你正在共享一个堆。您必须有办法手动释放从DLL分配的任何内存。

由于DLL边界问题导致我自己陷入困境,我建议您快速进行基准测试,以了解您在启用异常方面所支付的费用。根据您的平台和编译器,未经测试的异常可能会对性能产生非常微不足道的影响。