2009-10-28 13 views
8

別のDLLファイルを使用しているDLLファイルを使用しているEXEファイルがあります。このような状況が生じている:異なるDLLに割り当てられたメモリを解放する

をDLLファイル1では:DLLファイル2では

class abc 
{ 
    static bool FindSubFolders(const std::string & sFolderToCheck, 
           std::vector<std::string> & vecSubFoldersFound); 
} 

:リリースモードで

void aFunction() 
{ 
    std::vector<std::string> folders; 
    std::string sLocation; 
    ... 
    abc::FindSubFolders(sLocation, folders) 
} 

、すべてが正常に動作します。しかし、デバッグモードでは、私は、フォルダベクトル(フォルダがaFunctionの最後でスコープ外となる)でstd::stringsの一つのデストラクタでアサーションの失敗を思い付く:

dbgheap.c : line 1274

/* 
* If this ASSERT fails, a bad pointer has been passed in. It may be 
* totally bogus, or it may have been allocated from another heap. 
* The pointer MUST come from the 'local' heap. 
*/ 
_ASSERTE(_CrtIsValidHeapPointer(pUserData)); 

これは、メモリがDLLファイル1のヒープに割り当てられているが、DLLファイル2で解放されているためと思われます。

dbgheap.cのコメントはかなり問題があるようです。

なぜこのような問題がありますか?それを無視すれば正常に動作するように見えるのはなぜですか?これを行うアサーションに失敗した方法はありませんか?

+2

DONT。無視する。アサーション – KeatsPeeks

+22

NOT。無視する。それ。そうだ。なぜ。私は尋ねた。 = P – Smashery

+0

ちょうど知りたい*理由*それは問題です。 – Smashery

答えて

11

seanが既に述べたように、リリースビルドは単純にそのdelete文を無視するので、あなたが期待できるのはメモリリークです。

DLLファイルのコンパイル方法を管理している場合は、ランタイムライブラリのマルチスレッドデバッグDLL(/ MDd)またはマルチスレッドDLL(/ MD)設定を使用してください。こうすることで、両方のDLLファイルが同じランタイムシステムを使用し、同じヒープを共有します。

ランタイムシステムをアプリケーションと共にインストールする必要があるという欠点があります(マイクロソフトはそのためのインストーラを提供しています)。 Visual Studioではランタイムシステムもインストールされるため、開発マシンで正常に動作しますが、新しくインストールされたマシンでは不足しているDLLファイルが報告されます。

+0

プロジェクトのプロパティが間違っていました - デバッグDLL(/ MDd)が設定されていませんでした。ありがとう! – Smashery

6

ほとんどの場合、リリースビルドには同じ問題がありますが、リリースビルドはアサートされません。彼らはただ問題を無視します。問題が発生することはありません。または、データが破損することがあります。または、クラッシュが発生する可能性があります。たぶんあなたのユーザーだけがあなたが単に再現できないバグを経験するでしょう。

CRTアサーションを無視しないでください。

適切なデアロケータ(最初に使用したアロケータと一致するもの)を使用する必要があります。 DLLファイルで静的CRTライブラリを使用している場合、DLLファイルは異なるヒープを使用しています。ヒープ間でメモリの割り当てを解除することはできません。同じヒープを使用してメモリのブロックを割り当て、割り当てを解除します。

DLLファイルで共有CRTライブラリを使用している場合は、同じヒープを使用する必要があり、1つのDLLファイルに割り当てて別のDLLファイルに割り当てられます。

+2

cf. Raymond Chen:http://blogs.msdn.com/oldnewthing/archive/2006/09/15/755966.aspx –

+0

+1 - ありがとう! – Smashery

5

これは、アプリケーションまたは1つ(または複数)のDLLファイルが標準ライブラリの静的バージョンとリンクされている場合にのみ発生します。これは10年ほど前にMSが標準ライブラリの共有ライブラリ版をリリースすることで解決されました。これは、標準ライブラリの各バージョンが独自の内部ヒープを構築するため、複数のヒープで正しいヒープにメモリを解放する必要があるためです。標準ライブラリの共有バージョンを使用することにより、すべて同じヒープを使用します。

現在のアプリケーションでは標準的な慣行であり、すべてのDLLファイルは標準ライブラリの動的バージョンを使用するように構築する必要があります。

独自のヒープを作成し、このヒープからメモリを割り当てる場合にのみ注意が必要です。しかし、これはまれな状況でしか行われない非常に専門的な手順です(そして、それを使用するのに十分理解していれば、この質問をする状況にはなりません)。

6

他のところで言えば、問題は、CRTが2つのモジュール間で共有されていることを確認することで解決できます。しかし、この契約を強制するのは難しいという共通のシナリオがあります。

なぜなら、EXEとDLLが同じCRT バージョン(6.0,7.0,8.0など)とリンクしていないと、共有CRTとのリンクを確実にすることができないからです。たとえば、VC6.0でビルドされたDLLをVS2010でEXEビルドで使用しようとすると、以前と同じ問題が発生します。 CRTの2つのバージョンはプロセスにロードされ、それぞれのEXEとDLLが「共有」CRTを使用していても、同じではないにもかかわらず、割り当てにそれぞれ独自のヒープを使用します。

APIのより良い方法は、片側に割り当てられたオブジェクトも同じ側で破棄されるようにすることです。私はこれが醜いと思うが、DLLがバイナリ互換性を保つことを保証する唯一の方法です。

関連する問題