2013-02-06 27 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