Visual C++ 2013 Memory Leak Wostringstream, Imbue & locale facets

visual c++ 2013 memory leak wostringstream, imbue & locale facets

本文关键字:Imbue locale facets Wostringstream C++ 2013 Memory Leak Visual      更新时间:2023-10-16

与我之前的问题有关,我假设内存泄漏发生在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/300000句柄)。

以前,我认为这是一个与std::string有关的泄漏,但使用Visual Studio Profiler,它显示所有泄漏都是由GetUtf8Locale()引起的。

有人能帮我解决这个问题吗?

这个答案是错误的,我忽略了"比较";InterlockedCompareExchangePointer的一部分。然而,我认为这是朝着正确的方向迈出的一步

因此,我们从一个Log成员指向0x87654321的对象开始。然后两个线程调用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;