IXMLDOMElement::getAttributeでの_variant_t解放

[戻る]
846 2009/04/21(火) 23:51:35
MSXML4SP2のDOM/VS2005SP1を使用してXML読み込みを行うプログラムを作成しています。

プログラムの長時間動作でメモリの増加が見られたため、調査したところ、
raw_interfacesのgetAttribute関数で_variant_t値を取得する処理周りでリーク?のよ
うな動作があるように見えます。
getAttribute関数コールの前に_variant_tに値が入っている場合、その値が解放されな
いようなのです。

//↓↓↓↓以下サンプルコード抜粋

#import <msxml4.dll> named_guids raw_interfaces_only

// elmは既にyear属性のあるエレメントをセット
void CheckElementAttribute(MSXML2::IXMLDOMElement* elm) {
    HRESULT hr;
    _variant_t vr;
    while(1) {
        //getAttributeは成功して値取得する。
        hr = elm->getAttribute(_bstr_t(_T("year")), &vr);
        Sleep(50);
    }
}

//↑↑↑↑以上

上記の永久ループサンプルをタスクマネージャで見ているとじわじわメモリが増加して
いきます。このときgetAttribute直前にvr.Clear()を追加するとメモリが増加しなくな
りました。

MSDNのC++サンプル
(http://msdn.microsoft.com/ja-jp/library/ms761380(en-us,VS.85).aspx)
など見る限り、事前のvr.Clear()が必須にも思えないので、
どこかに私の勘違いがあるような気が否めません。

何かご存知の方、ご教授いただければ幸いです。

Blue 2009/04/22(水) 08:48:41
while文ブロック内で宣言してみては?
_variant_tクラスのコンストラクタが自動的に解放するようになっているので、
MSDNのサンプルでClearメソッドを読んでいないのでしょう。

846 2009/04/22(水) 10:50:10
だめなようです。
下記のようにサンプル修正しましたが同様でした。
//↓↓↓↓以下サンプルコード抜粋

#import <msxml4.dll> named_guids raw_interfaces_only

// elmは既にyear属性のあるエレメントをセット
void CheckElementAttribute(MSXML2::IXMLDOMElement* elm) {
    HRESULT hr;

    while(1) {
        _variant_t vr;
        vr = _T("test");
        //getAttributeは成功して値取得する。
        hr = elm->getAttribute(_bstr_t(_T("year")), &vr);
        Sleep(50);
    }
}

//↑↑↑↑以上
通常では_variant_tクラスは値が入力された際に前値Clear()をするようです。
ついでに関数内部のwhileを削除してCheckElementAttribute関数をループさせても同様
でした。

subaru 2009/04/22(水) 11:32:36
>通常では_variant_tクラスは値が入力された際に前値Clear()をするようです。

確かに_variant_tクラスは値の代入やデストラクタで値をクリアしますが、

>        //getAttributeは成功して値取得する。
>        hr = elm->getAttribute(_bstr_t(_T("year")), &vr);

ここで第2引数で実際に渡されている型はVARIANT*です。

つまりgetAttributeの実装がVariantClearを呼んでないならリークするんじゃないでしょ
うか。
事前にvr.Clear()を呼ぶが正解なのでは?

846 2009/04/22(水) 12:13:28
[[解決]]
確かにおしゃっる通りの気がしてきました。
前述のMSDNのサンプルソース自体、かなりデタラメなようです。

素直にClear()しておきます。

ご教授どうもありがとうございました。

wclrp ( 'o') 2009/04/22(水) 21:51:19
以下は推測やうろ覚え。
間違えかもしれない。

HRESULT getAttribute(
    BSTR name,
    VARIANT *value);

value[out, retval]

出力兼戻り値であり、VARIANTへのポインタだから、
getAttribute内で作られたVARIANTが返されるんでしょ。

[in,out] VARIANT * valueで、
呼び出し先が値を変更する場合であり
それが新たにメモリ確保が必要ならば
解放して新しいVARIANTを返すことはある。

どのみち、getAttribute内でvalue->Clear()は期待しない方がいいみたい。

サンプルが厳密なエラーチェックやメモリ解放していなくて
間違えて理解したということはよくあるね。
サンプルだからいいじゃないかというのもあるし、
間違えが広まるから困るというのもある。
ちょっとした説明で大量の余計な処理があるサンプルは使いにくいし
ややこしいところだな。

ネットに情報が多すぎるし、とくに特徴のない普通の英単語だし、
同じ単語のものがJava用、MSXML用、.NET用といろいろあり
なかなか検索で見つけるの大変だな。

wclrp ( 'o') 2009/04/23(木) 09:35:13
> [in,out] VARIANT * valueで、
これは
もしも[in,out] VARIANT * valueだったらって話。

[out]、[out,retuval]ってなっているものは
解放済みVARIANTにすべきみたいだね。

古いスレッドには追加発言できません。