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

C++ VS2012编译器奇怪的内存释放问题,c++,windows,memory,visual-studio-2012,memory-management,C++,Windows,Memory,Visual Studio 2012,Memory Management,我对VS2012编译器有一个奇怪的问题,它似乎没有出现在GCC中。解除分配过程最终需要几分钟而不是几秒钟。有人对此有什么意见吗?步骤调试显示对RtlpCollectFreeBlocks()的调用出现明显挂起。我在调试和发布模式下都有这个问题。我运行的是32位Windows 7,但在64位7上也有同样的问题 #include "stdafx.h" #include <iostream> #include <stdint.h> #include <cstdlib>

我对VS2012编译器有一个奇怪的问题,它似乎没有出现在GCC中。解除分配过程最终需要几分钟而不是几秒钟。有人对此有什么意见吗?步骤调试显示对RtlpCollectFreeBlocks()的调用出现明显挂起。我在调试和发布模式下都有这个问题。我运行的是32位Windows 7,但在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;
}
#包括“stdafx.h”
#包括
#包括
#包括
#定义大小500000
使用名称空间std;
类型定义结构
{
uint32_t*thing1;
}收藏;
/*
*使用VS2012编译器。
*场景:
*1)不要分配东西。程序运行得很差。
*2)分配内容1,但不要删除它。程序运行得很好。
*3)分配内容1并将其删除。程序运行得很差。
* 
*调试或发布模式不影响结果。GCC的编译器很好。
*/
int _tmain(int argc,_TCHAR*argv[]
{
集合**colArray=新集合*[SIZE];
对于(int i=0;ithing1=new uint32\u t;//分配而不释放运行正常。A)不分配或B)分配并删除以使其运行缓慢。
colArray[i]=我的;
}

cout您所看到的性能冲击来自Windows调试堆功能,它在如何启用自身方面有点隐秘,即使是在发布版本中

我冒昧地构建了一个简单程序的64位调试映像,并发现:

  • msvcr110d.dll_CrtIsValidHeapPointer(常量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!运算符删除(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) );
这个电话太残酷了

好吧,也许我会在调试版本中看到这一点。但肯定不会释放。事实证明,这会变得更好,但看看调用堆栈:

  • ntdll.dll!RtlDebugFreeHeap()
  • ntdll.dll!字符串“启用堆调试选项\n”()
  • ntdll.dll!RtlFreeHeap()
  • 内核32.dll!堆
  • msvcr110.dll!自由(无效*pBlock)
这很有趣,因为当我第一次运行它,然后用IDE(或WinDbg)连接到正在运行的进程,而不允许它控制执行启动环境时,这个调用堆栈在
ntdll.dll处停止!RtlFreeHeap()
。换句话说,不会调用在IDE
RtlDebugFreeHeap
之外运行的代码。但是为什么呢

我心里想,调试器不知何故正在翻转开关以启用堆调试。在做了一些挖掘之后,我发现“开关”就是调试器本身。如果正在运行的进程是由调试器生成的,Windows将使用特殊的调试堆函数(
rtldebugalloweap
RtlDebugFreeHeap
)。回避这一点,以及关于在Windows下调试的其他有趣的小道消息:

使用WinDbg调试用户模式进程

调试器创建的进程(也称为衍生进程)的行为与调试器不创建的进程略有不同

调试器创建的进程不使用标准堆API,而是使用特殊的调试堆。通过使用_NO_debug_heap环境变量或-hd命令行选项,可以强制生成的进程使用标准堆而不是调试堆

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


根据那篇文章的内容,我已经自由地更新了我的发布模式版本,以便在项目文件的执行环境设置中定义
\u NO\u DEBUG\u HEAP=1
。我显然仍然对调试构建中的粒度堆活动感兴趣,所以这些配置保持原样。这样做之后,我的版本在VS2012(VS2010)下运行的速度大大加快了,我也邀请你去尝试。

在堆上分配一个int是不一般的C++,如果你按值存储它会有帮助吗?这只是一个简单的例子。我最初在结构中有4个uint32\t。这个想法是为了表明结构的大小对于这个问题似乎并不重要。@Sean在
size
上使用二进制搜索是否有一个性能显著提高的点?它显然与ide挂钩有关。切换到cmd提示符并从控制台运行程序。完全没有问题,内存模型和调试状态也没有区别