2013-02-06 25 views
10

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

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

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

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

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

感谢您的建议。

+0

* DLL是否使用单独的内存池?* http://stackoverflow.com/questions/10820114/do-statically-linked-dlls-use-a-different-heap-than-the-main-program – thang

+0

*如果是这样的话,我可以在不需要应用程序卸载DLL的情况下清除它吗?是的,只需从new中删除这些东西,然后从malloc中释放这些东西。 – thang

+1

没有异常处理意味着堆栈上(以及失败的构造函数内)创建的对象不会被销毁。如果你只是在'bad_alloc'发生时退出,那么你很好,我想[只要你没有奇怪的资源,不会被程序退出清理 - 但大多数应该]。如果你想在'bad_alloc'后面“继续”,那么代码将需要跟踪对象并销毁在'throw'和'catch'之间的栈帧中创建的所有对象。你可以通过编写一些在解析器中打印输出的小代码来体验。 –

回答

1

几个预赛:

我不知道,如果抛出一个异常无一例外处理启用的是标准定义的操作或没有,但你肯定不会得到你的对象堆栈展开/析构函数调用在堆栈上。

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

谈完话,并假设你的代码基本上是C风格代码:

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

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

由于DLL边界问题让我自己陷入了太多的困境,所以我会推荐一个快速基准测试来查看您在启用了例外情况方面所付出的代价。取决于您的平台和编译器,可变形的异常可能会对性能产生不可忽视的影响。

+0

这不是C风格的代码,其中很大一部分不受我控制。尽管我在正常操作下相信这个第三方代码,但是当抛出一个OOM异常时,我不认为我可以做出任何假设,无论是否启用异常处理。 “_您将不得不手动释放从DLL中分配的任何内存。”这正是我的问题所在。 :-) –

+0

对不起,但我想那时真的没有办法做你想做的事。要在我自己的插件类型系统中实现“从DLL中手动发布”,我需要使用我的核心提供给DLL的自定义分配例程来分配所有客户端代码。这个关联允许核心像你想要的那样放下一个DLL。但是如果你不能自己执行这个,那么我认为它不能完成。 – Stephen