-1

前回の質問に関連して、std::string でメモリ リークが発生すると想定していましたが、詳しく調べてみると、奇妙な結果が得られました。さぁ、始めよう:

グローバルがあると考えてください

static volatile std::wostringstream *Log = nullptr;

WriteToLog() 関数には、次のコードがあります。

    std::wostringstream* new_log = new std::wostringstream(std::ios::in | std::ios::out);
    new_log->imbue(CConsumer::GetUtf8Locale());

    std::wostringstream* old_log = (std::wostringstream*)Log;

    while((std::wostringstream *)::InterlockedCompareExchangePointer((PVOID volatile *)&Log, new_log, (PVOID)old_log) != new_log)
    {
        ::SleepEx(10, FALSE);
    }

    std::string logtext(Hooker::Utf16ToUtf8(old_log->str()));

これは独自のものを利用します:

    static std::locale FORCEINLINE GetUtf8Locale()
    {
        static std::unique_ptr<std::codecvt_utf8_utf16<wchar_t>> code_cvt(new std::codecvt_utf8_utf16<wchar_t>(std::codecvt_mode::generate_header | std::codecvt_mode::little_endian));
        return std::locale(std::locale(), code_cvt.get());
    }

ログ イベントは時折発生するため、大量のメモリ リークが発生します (最初の 5MB/500 ハンドルから、数分で 200MB/300,000 ハンドルにジャンプします)。

以前は、std::string に関するリークであると想定していましたが、Visual Studio Profiler を使用して、すべてのリークが GetUtf8Locale() によって引き起こされていることを示しています。

誰でもこの問題で私を助けることができますか?

4

1 に答える 1

0

この答えは間違っていて、InterlockedCompareExchangePointer の「比較」の部分を見落としていました。しかし、それは正しい方向への一歩だと思います。

Logそのため、メンバが を指しているオブジェクトから始めます0x87654321。次に、2 つのスレッドが呼び出されますWriteToLog

Thread1                                Thread2
...new_log=new ... 
(now new_log=0x15331564)
                                       ...new_log=new ...
                                       (now new_log=0x25874963)
...old_log=Log;
(now old_log=0x87654321)
                                       ...old_log=Log;
                                       (now old_log=0x87654321)

InterlockedCompareExchangePointer
(now new_log=0x87654321)
(now Log=0x15331564)

                                       InterlockedCompareExchangePointer
                                       (now new_log=0x15331564)
                                       (now Log=0x25874963)
...stuff...                            ...stuff...
delete old_log 
(now 0x87654321 is deleted)
                                       delete old_log
                                       (now 0x87654321 is deleted TWICE!)

そしてLogメンバーが を指さす0x25874963ので… ログ0x15331564が流出!

の使い方InterlockedCompareExchangePointerが間違っています。あなたが示していないコードによっては、これは正しいと思います。

std::wostringstream* new_log = new std::wostringstream(std::ios::in | std::ios::out);
new_log->imbue(CConsumer::GetUtf8Locale());

std::wostringstream* old_log = ::InterlockedExchangePointer((PVOID volatile *)&Log.get(), new_log);

std::string logtext(Hooker::Utf16ToUtf8(old_log->str()));

delete old_log;
于 2015-03-31T17:21:05.030 に答える