gpt4 book ai didi

c++ - VS2012编译器奇怪的内存释放问题

转载 作者:可可西里 更新时间:2023-11-01 13:22:54 24 4
gpt4 key购买 nike

我在使用 VS2012 编译器时遇到了一个奇怪的问题,它似乎没有出现在 GCC 中。重新分配过程最终需要几分钟而不是几秒钟。有人对此有任何意见吗?单步调试显示调用 RtlpCollectFreeBlocks() 时明显挂起。我在调试和 Release模式下都有这个问题。我正在运行 Windows 7 32 位,但我在 64 位 7 上遇到同样的问题。

#include "stdafx.h"
#include <iostream>
#include <stdint.h>
#include <cstdlib>

#define SIZE 500000

using namespace std;

typedef struct
{
uint32_t* thing1;
}collection;

/*
* VS2012 compiler used.
* Scenarios:
* 1) Don't allocate thing1. Program runs poorly.
* 2) Allocate thing1 but don't delete it. Program runs awesome.
* 3) Allocate thing1 and delete it. Program runs poorly.
*
* Debug or Release mode does not affect outcome. GCC's compiler is fine.
*/
int _tmain(int argc, _TCHAR* argv[])
{
collection ** colArray = new collection*[SIZE];

for(int i=0;i<SIZE;i++)
{
collection * mine = new collection;
mine->thing1 = new uint32_t; // Allocating without freeing runs fine. Either A) don't allocate or B) allocate and delete to make it run slow.
colArray[i] = mine;
}

cout<<"Done with assignment\n";

for(int i=0;i<SIZE;i++)
{
delete(colArray[i]->thing1); // delete makes it run poorly.
delete(colArray[i]);

if(i > 0 && i%100000 == 0)
{
cout<<"100 thousand deleted\n";
}
}
delete [] colArray;

cout << "Done!\n";
int x;
cin>>x;
}

最佳答案

您看到的性能下降来自 Windows 调试堆功能,它在如何启用自身方面有点隐秘,即使在发布版本中也是如此。

我冒昧地构建了一个更简单程序的 64 位调试镜像,然后发现了这一点:

  • msvcr110d.dll!_CrtIsValidHeapPointer(const void * pUserData=0x0000000001a8b540)
  • msvcr110d.dll!_free_dbg_nolock(void * pUserData=0x0000000001a8b540, int nBlockUse=1)
  • msvcr110d.dll!_free_dbg(void * pUserData=0x0000000001a8b540, int nBlockUse=1)
  • msvcr110d.dll!operator delete(void * pUserData=0x0000000001a8b540)

我特别感兴趣的是 msvcr110d.dll!_CrtIsValidHeapPointer 的主体,结果是这样的:

if (!pUserData)
return FALSE;

// Note: all this does is checks for null
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;

// but this is e-x-p-e-n-s-i-v-e
return HeapValidate( _crtheap, 0, pHdr(pUserData) );

那个HeapValidate()电话是残酷的。

好吧,也许我会在调试版本中期待这一点。但肯定不会释放。事实证明,情况会好转,但请查看调用堆栈:

  • ntdll.dll!RtlDebugFreeHeap()
  • ntdll.dll!string "启用堆调试选项\n"()
  • ntdll.dll!RtlFreeHeap()
  • kernel32.dll!HeapFree()
  • msvcr110.dll!free(void * pBlock)

这很有趣,因为当我先运行它,然后使用 IDE(或 WinDbg)附加到正在运行的进程,不允许它控制执行启动环境时,这个调用堆栈停止在 ntdll.dll!RtlFreeHeap( )。换句话说,在 IDE 之外运行 RtlDebugFreeHeap 不会被调用。但是为什么??

我心想,不知何故调试器正在翻转一个开关以启用堆调试。在做了一些挖掘之后,我发现“开关”就是调试器本身。如果正在运行的进程是由调试器生成的,Windows 将使用特殊的调试堆函数(RtlDebugAllocHeapRtlDebugFreeHeap)。 This man-page from MSDN on WinDbg回避这一点,以及有关在 Windows 下调试的其他有趣花絮:

from Debugging a User-Mode Process Using WinDbg

Processes that the debugger creates (also known as spawned processes) behave slightly differently than processes that the debugger does not create.

Instead of using the standard heap API, processes that the debugger creates use a special debug heap. You can force a spawned process to use the standard heap instead of the debug heap by using the _NO_DEBUG_HEAP environment variable or the -hd command-line option.

现在我们有所进展。为了对此进行测试,我简单地删除了一个 sleep() 并留出适当的时间让我附加调试器,而不是用它生成进程,然后让它以愉快的方式运行。果然,如前所述,它全速前进。

根据那篇文章的内容,我已自行更新我的 Release模式构建,以在我的项目文件的执行环境设置中定义 _NO_DEBUG_HEAP=1。显然,我仍然对调试版本中的颗粒堆事件感兴趣,因此这些配置保持原样。执行此操作后,我在 VS2012(和 VS2010)下运行的发布构建的整体速度显着更快,我邀请您也尝试一下。

关于c++ - VS2012编译器奇怪的内存释放问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18745968/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com