与我之前的问题相关,我假设在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()引起的。
有人可以帮我解决这个问题吗?
答案 0 :(得分:0)
因此,我们从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
,所以...... log 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;