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?
注 - 2GBのRAMを持つのVisual Studio 2008 SP1、Core 2 Duoプロセッサ6700 CPU
。を追加しました:を明確にするために、いいえ、私は混乱していないよDebugとReleaseビルド。これらの結果は、さらに任意の中間に再コンパイルすることなく、一つの同じ.exeの上にあります。実際には、デバッグとリリースの切り替えは、変更の何を構築しません。
解決
デバッガで実行すると、より多くのチェックを行い1に使用されるメモリ割り当てライブラリを変更します。メモリの割り当てと割り当て解除が、何もしないプログラムでは、「通常の」プログラムよりもはるかに苦しむするつもりです。
編集 ちょうど私が
のように見えるコールスタックを取得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の内部からこれを試すことができます。デバッグなしでまったく同じビルド構成と実行して、コマンドラインからのようです。
デバッガでプログラムを起動したときにデバッガで既に実行中のプログラムにアタッチとは対照的に、デバッグヒープは自動的に、有効になります。
マリオ・ヘワートとダニエルPravatの著書の高度なWindowsのデバッグする のは、いくつかを持っていますWindowsのヒープについてのまともな情報が、それはヒープ上の章があることが判明したアップなどのウェブサイト上でサンプル章でます。
ページ281は、「デバッガの下でプロセスの起動バーサス取り付け」に関するサイドバーがあります:
の下で処理を開始すると デバッガ、ヒープマネージャの修正 新しいヒープを作成するためのすべての要求と へのヒープの作成フラグを変更 デバッグに優しいヒープを有効にする(しない限り、 _NO_DEBUG_HEAP環境 変数)が1に設定されています。比較において、 既に実行中にアタッチ プロセス、プロセス内のヒープを持っています すでにデフォルトを使用して作成されて ヒープの作成フラグと持っていません。 (しない限り、設定のデバッグに優しいフラグ 明示的に)アプリケーションによって設定されます。
(また:I 半関連する質問する、前にこの答えの一部を掲載した。)
これは、これを減速だと間違いなくHeapFreeだ、あなたは以下のプログラムと同じ効果を得ることができます。
HeapFreeにHEAP_NO_SERIALIZEのようなパラメータを渡すと、いずれか助けていません。
#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 の/窓抗デバッグ参照
"!PEB NtGlobalFlags" セクション2を読み、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、2GBのRAMを持つCore 2 Duoプロセッサ6700 CPUます。
私には意味がありません。