2017-09-14 36 views
0

私が取り組んでいるこのプログラムではメモリリークがあり、コミットに関する限りかなりの時間待っています。これらの2つの説明によれば、_bstr_tで=代入演算子を使用すると、メモリリークが発生するたびにexplanation 1explanation 2が発生します。_bstr_tを使用したメモリリーク

コンテキスト - データベースのクイックSQLクエリを実行するためによく使用されるデータベースオブジェクトがあります。すべてのメソッドは、最終的には、この方法は、データに原因で_bstr_tのデータベースを照会するために呼ばれていますし、彼らがどのように作成されるたびにリークします記事によると、以下の方法に

NvStatus DbUtils::ReadFromDatabase(IUnknown * poNvData, 
            const std::wstring & oConnectString, 
            const std::wstring & oSQLStatement) 
{ 
    //some checks 
    _bstr_t tbtSQLStr = oSQLStatement.c_str();//memory leak 
    _bstr_t tbtConnStr = oConnectString.c_str();//memory leak 

    //pass the _bstr_t to another method and get data from DB 
    return status; 
} 

を使用しています。私の質問は、プログラムが爆発するのを防ぎ、_bstr_tオブジェクトにガベージコレクションを強制するために何ができるのでしょうか?

Microsoftは、使用した後でメモリをクリーンアップするのは私の責任だと言いますが、データを壊すことなくどのようにすればいいですか?私は文字列の深いコピーをしようとしたが、それは失敗した...任意の提案は非常に感謝される!

さらに調査した後、私のメモリリークのための2つのホットスポットは、私が最初に投稿1と、この一つであり、これは

static bool GetValueFromVariant(VARIANT & tvInputValue, 
    std::wstring & roOutputValue) 
{ 
    _bstr_t tTemp = tvInputValue.bstrVal; 
    if(tTemp.length()>0) 
    { 
     roOutputValue = (wchar_t*) tTemp; 
    } 
    return true; 
} 

コメントはこれらの_bstr_tが...しかし、ときに自動的に自分自身をクリーンアップする必要があることを示唆しているのに役立ちます願っています私のWindowsサービスのヒープサイズをデバッグすると、ヒープサイズは絶えず増加し、デバッガはこれらの_bstr_tオブジェクトをすべて使用する関数を指し続けます。明らかにこれらの_bstr_tはクリーンアップされていません。

このメモリリークの大部分は、COMオブジェクトの繰り返し作成に由来しますが、オブジェクトを解放するときに、Release()関数呼び出しから返された参照カウントを確認します。したがって、私はCOMオブジェクトのビルドアップを持っていないことを知っています...

_bstr_tのアドレスにwstringを指すときに問題がありますか?

+0

'_bstr_t'は、ネイティブ' BSTR'sのためのスマートなラッパーで、メモリの割り当てと解放を処理します。したがって、デストラクタがこれを処理するので、 '_bstr_t'で' SysFreeString'を呼び出すはずがありません。 – Aurora

+0

その後、メモリリークが発生した場合、メモリリークが発生します。私はvs2015デバッガをアタッチしており、これらの_bstr_tオブジェクトを使用しているすべてのものからメモリが増加しています...なぜそれらはクリーンアップされていませんか?ガベージコレクションを強制する方法はありませんか? @Aurora –

+0

私は私の質問が沸騰すると思う - とにかく新しいを呼び出すことなくbstrを使用するのですか? @Aurora –

答えて

0

例の最初の行は、Cスタイルの文字列を_bstr_tラッパーに割り当てているため、メモリがリークしません。以前割り当てられたBSTR_bstr_tに割り当てると、状況が違って見えます。これは問題です。これは2番目の説明で説明しています。ネイティブBSTRSysAllocStringを使用して割り当てられ、S1内に配置され、ここで

void foo() 
{  
    BSTR s1 = SysAllocString(L"String1"); 
    _bstr_t s2 = s1; 
} 

は、次の場合を考えます。次の行はs1から新しいBSTRを構築します。これはs2に置かれます。スコープから外れると、そのデストラクタはSysFreeStringを呼び出し、コピーの割り当てを解除します。しかし、元のs1変数は元のままであり、リークします。

これを解決するには、s2がS1の所有権を取得できるようにする必要があります:

void foo() 
{ 
    BSTR s1 = SysAllocString(L"String1"); 
    _bstr_t s2(s1, false); 
} 

または

void foo() 
{ 
    BSTR s1 = SysAllocString(L"String1");   
    _bstr_t s2; 
    s2.Attach(s1); 
} 

私のコメントで示されているように、_bstr_tのデストラクタがSysFreeStringを呼び出します、それによって、リソースの割り当てを解除します。

通常、BSTRがキャッシュされているため、メモリの割り当て解除をすぐに確認することはできません。この動作は、setting an environment variableによってデバッグの目的で無効にすることができます。

+0

あなたは、それらの文字列に使用されているメモリの割り当てを解除する必要があると言いましたが、決してそうしません...このプログラムは、使用可能なメモリがすべてシステムによって使い切られるまでメモリをリークし続けます。もう一度このプログラムはWindowsサービスであり、違いがあるかどうかはわかりません。また、vs2015デバッガに応じてリークするコードのセクションも追加しました。 –

+0

別の考え方: '_bstr_t'は参照カウントです。おそらく '_bstr_t'を値でメソッドやクラスのインスタンスに渡していますか? ref-countがまだ0に達していないので、dtorがトリガーされない理由は、考えられる説明です。 – Aurora

+0

これは、COMオブジェクトが作成され、作成された時点で既に存在するかどうかが再初期化され、再初期化の手順によって上記のメソッドへの呼び出しが発生するために発生します。おそらくオブジェクトのサイズが増えていますが、vs2015デバッガによれば、すべての変数のサイズは同じですが、スナップショットごとにヒープスペースが増えます。 –

0

最初のケースでは、SysFreeStringを呼び出さないでください。メモリリークはありません。

で使用されるコンストラクタ:

_bstr_t tbtSQLStr = oSQLStatement.c_str(); 

は、元の文字列のコピーを作成し、tbtSQLStrがスコープの外に出るときは、このコピーはデストラクタの呼び出しによって解放されます。クラス型ラッパーを使用することの全ポイントは、手動でSysFreeStringを呼び出す必要はありません。

// ....ブロックのコードの性質によっては、この文字列のコピーを作成する必要がない場合もあります。


2番目のケース(2番目の質問を投稿したはずの最初のケースとは別の質問です)、メモリリークもありません。

tTempはコピーを割り当てます。 roOutputValueコピーし、次にtTempのデストラクタが最初のコピーを解放します。

あなたが作成し、tTempを破壊することで時間を無駄しかし、あなただけ書かれている可能性:

私は「実際のコードを」と仮定してい
if (SysStringLen(tvInputValue.bstrVal) > 0) 
    roOutputValue = tvInputValue.bstrVal; 

は実際にバリアントが、この時点でBSTRを保持してチェックします。

+0

はい、sysallocとsysfreeはBSTRに意味があり、_bstr_tは私のためにこれを行うラッパーです。第2に、下部のコードはプロジェクト内のコードを逐語的に表しています。最後に、私のコードにリモートデバッガをアタッチすると、ReadFromDatabaseとGetValueFromVariantから最も大きなサイズのスタックビューを表示する唯一の2つのスポット...変数のサイズはすべて同じままですが、メモリは増加します。 。 –

+0

さらに、私はスタックビューを通過し、ドロップダウンを使用して、ヒープスペースのサイズの増加が_bstr_tに由来する場所を確認すると、_bstr_t :: _ bstr_t - > _bstr_t :: Data_t :: Data_tです。これらの_bstr_tの私はデバッガでそれをはっきりと見ることができます –

+0

@RAZ_Muh_Taz OK、実際にbstrを使用する前に、 'VT_BSTR'がバリアント型であることを確認するコードを追加してください –

関連する問題