C ++析构函数的怪异的行为
-
22-08-2019 - |
题
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector< vector<int> > dp(50000, vector<int>(4, -1));
cout << dp.size();
}
这个小程序需要一秒钟时执行简单的命令行运行。但是,在一个调试器中运行时,它接管8秒。暂停调试器显示,它在摧毁一切的矢量的中间。 WTF?
注 - 的Visual Studio 2008 SP1,酷睿2 6700 CPU的RAM 2GB
补充:要澄清一下,不,我不是混淆调试和发布版本。这些结果是在同一个.exe文件,甚至没有任何重新编译其间。事实上,调试和发布之间的切换建立变化无关。
解决方案
运行在调试器改变用于一个没有更大量检查内存分配库。什么也不做,但内存分配和释放的程序是要遭受比“正常”程序等等。
修改强> 刚刚试过VS下运行您的程序,我得到一个调用堆栈,看起来像
ntdll.dll!_RtlpValidateHeapEntry@12() + 0x117 bytes
ntdll.dll!_RtlDebugFreeHeap@12() + 0x97 bytes
ntdll.dll!_RtlFreeHeapSlowly@12() + 0x228bf bytes
ntdll.dll!_RtlFreeHeap@12() + 0x17646 bytes
msvcr90d.dll!_free_base(void * pBlock=0x0061f6e8) Line 109 + 0x13 bytes
msvcr90d.dll!_free_dbg_nolock(void * pUserData=0x0061f708, int nBlockUse=1)
msvcr90d.dll!_free_dbg(void * pUserData=0x0061f708, int nBlockUse=1)
msvcr90d.dll!operator delete(void * pUserData=0x0061f708)
desc.exe!std::allocator<int>::deallocate(int * _Ptr=0x0061f708, unsigned int __formal=4)
desc.exe!std::vector<int,std::allocator<int> >::_Tidy() Line 1134 C++
其示出了NTDLL.DLL调试功能和所使用的C运行。
其他提示
附加了调试器中运行的程序总是比没有慢。
这必须由VS挂钩到新/删除调用和做更多的检查连接时引起的 - 或运行时库使用的IsDebuggerPresent API和做事的不同在这种情况下
您可以轻松地在Visual Studio中尝试这个,开始调试 - >启动调试或者调试 - 程序>不开始调试。无需调试就像是从命令行中,具有完全相同的生成配置和可执行的。
在调试堆,当你在调试器中启动程序自动启用获取,而不是连接到一个已经运行的程序与调试器。
这本书的 高级Windows调试 的由马里奥·赫沃特和丹尼尔Pravat有一些有关Windows堆体面的信息,并且事实证明,上堆的一章是了在网站上的样章。
页面281具有大约侧边栏“连接对战开始处理下调试器”:
当开始下的过程 调试器,堆管理器修改 所有请求创建新的堆和 更改堆创建标志,以 启用调试友好堆(除非 该_NO_DEBUG_HEAP环境 变量设置为1)。相比下, 连接到已经运行 过程,在这个过程中堆有 已经使用默认创建的 堆创建标志,而且不会有 设置调试友好的标志(除 明确地由应用程序设置)。
(也:半相关问题,其中I帐前此答案的一部分。)
这绝对HeapFree多数民众赞成放缓下来,你可以用下面的程序相同的效果。
传参数,如HEAP_NO_SERIALIZE到HeapFree也没有帮助。
#include "stdafx.h"
#include <iostream>
#include <windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE heap = HeapCreate(0, 0, 0);
void** pointers = new void*[50000];
int i = 0;
for (i = 0; i < 50000; ++i)
{
pointers[i] = HeapAlloc(heap, 0, 4 * sizeof(int));
}
cout << i;
for (i = 49999; i >= 0; --i)
{
HeapFree(heap, 0, pointers[i]);
}
cout << "!";
delete [] pointers;
HeapDestroy(heap);
}
http://www.symantec.com/connect/articles /窗口 - 反调试参考
读取部2 “PEB!NtGlobalFlags” 和2 “堆标志”
想,这也许可以解释它...
编辑:加入溶液
在您的处理程序CREATE_PROCESS_DEBUG_EVENT,添加以下
// hack 'Load Configuration Directory' in exe header to point to a new block that specfies GlobalFlags
IMAGE_DOS_HEADER dos_header;
ReadProcessMemory(cpdi.hProcess,cpdi.lpBaseOfImage,&dos_header,sizeof(IMAGE_DOS_HEADER),NULL);
IMAGE_OPTIONAL_HEADER32 pe_header;
ReadProcessMemory(cpdi.hProcess,(BYTE*)cpdi.lpBaseOfImage+dos_header.e_lfanew+4+sizeof(IMAGE_FILE_HEADER),&pe_header,offsetof(IMAGE_OPTIONAL_HEADER32,DataDirectory),NULL);
IMAGE_LOAD_CONFIG_DIRECTORY32 ilcd;
ZeroMemory(&ilcd,sizeof(ilcd));
ilcd.Size = 64; // not sizeof(ilcd), as 2000/XP didn't have SEHandler
ilcd.GlobalFlagsClear = 0xffffffff; // clear all flags. this is as we don't want dbg heap
BYTE *p = (BYTE *)VirtualAllocEx(cpdi.hProcess,NULL,ilcd.Size,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
WriteProcessMemory(cpdi.hProcess,p,&ilcd,ilcd.Size,NULL);
BYTE *dde = (BYTE*)cpdi.lpBaseOfImage+dos_header.e_lfanew+4+sizeof(IMAGE_FILE_HEADER)+offsetof(IMAGE_OPTIONAL_HEADER32,DataDirectory)+sizeof(IMAGE_DATA_DIRECTORY)*IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
IMAGE_DATA_DIRECTORY temp;
temp.VirtualAddress = p-cpdi.lpBaseOfImage;
temp.Size = ilcd.Size;
DWORD oldprotect;
VirtualProtectEx(cpdi.hProcess,dde,sizeof(temp),PAGE_READWRITE,&oldprotect);
WriteProcessMemory(cpdi.hProcess,dde,&temp,sizeof(temp),NULL);
VirtualProtectEx(cpdi.hProcess,dde,sizeof(temp),oldprotect,&oldprotect);
对,WTF确实
您知道您的编译器将通过内联他们优化了大量的函数调用,然后进一步优化代码中有排除任何东西,实际上并没有做任何事情,这在为int的载体的情况下将意味着:几乎也不是很多。
在调试模式下,内联不导通,因为这将使得调试可怕。
这是真的有多快C ++代码可以是一个很好的例子。
8秒??我试图在调试模式下是相同的。不超过半秒,我猜。你确定它的析构函数?
FYI。的Visual Studio 2008 SP1,酷睿2 6700 CPU的RAM 2GB。
是没有意义的我 - 在正常构造附加调试器来随机二进制应该大多只是陷阱断点中断(INT ASM 3等)