Question

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector< vector<int> > dp(50000, vector<int>(4, -1));
    cout << dp.size();
}

Ce petit programme prend une fraction de seconde pour exécuter lorsque simplement courir à partir de la ligne de commande. Mais lorsqu'il est exécuté dans un débogueur, il faut plus de 8 secondes. Le débogueur révèle une pause qu'il est au milieu de détruire tous ces vecteurs. WTF?

Remarque -. Visual Studio 2008 SP1, Core 2 Duo 6700 CPU avec 2 Go de RAM

Ajouté: Pour clarifier, non, je ne suis pas confondre Debug et Release builds. Ces résultats sont sur une seule et même .exe, sans même aucune recompilation inbetween. En fait, la commutation entre Debug et Release builds ne change rien.

Était-ce utile?

La solution

L'exécution dans le débogueur modifie la bibliothèque d'allocation de mémoire utilisée pour celui qui fait beaucoup plus le contrôle. Un programme qui ne fait que l'allocation de mémoire et désallocation va souffrir beaucoup plus qu'un programme « normal ».

Modifier Ayant tout essayé l'exécution de votre programme sous VS je reçois une pile d'appel qui ressemble à

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++

Ce qui montre les fonctions de débogage dans ntdll.dll et le runtime C utilisé.

Autres conseils

L'exécution d'un programme avec le débogueur attaché est toujours plus lent que sans.

Il doit être causée par VS accrochage dans la nouvelle / supprimer des appels et faire plus de vérifier lorsqu'il est attaché -. Ou la bibliothèque d'exécution utilise l'API IsDebuggerPresent et fait des choses différentes dans ce cas,

Vous pouvez facilement essayer de l'intérieur de Visual Studio, démarrez le programme avec Debug-> Démarrer le débogage ou Debug-> Démarrer sans débogage. Sans mise au point est comme de la ligne de commande, avec exactement la même configuration de construction et exécutable.

Le tas de débogage est automatiquement activé lorsque vous démarrez votre programme dans le débogueur, par opposition à la fixation à un programme déjà en cours d'exécution avec le débogueur.

Le livre de Mario Hewardt et Daniel Pravat de Windows Débogage avancé a quelques-uns informations sur le tas décent de Windows, et il se trouve que le chapitre sur des tas est sur le site Web en tant que chapitre échantillon .

Page 281 a une barre latérale de "Fixation Versus Démarrage du processus Sous le Debugger":

  

Lors du démarrage du processus sous la   débogueur, le gestionnaire modifie tas   toutes les demandes de créer de nouveaux tas et   changer les drapeaux de création de tas à   permettre à des tas de débogage de l'environnement (à moins que   l'environnement _NO_DEBUG_HEAP   la variable est définie sur 1). En comparaison,   fixer à un fonctionnement déjà   processus, les tas dans le processus ont   déjà été créée à l'aide par défaut   drapeaux de création tas et ne pas   les drapeaux de débogage convivial sertis (à moins que   explicitement défini par l'application).

(aussi: question liée semi-où je posté une partie de cette réponse avant.)

Il est certainement HeapFree qui est le ralentissement de cette baisse, vous pouvez obtenir le même effet avec le programme ci-dessous.

paramètres comme HEAP_NO_SERIALIZE à Passing HeapFree ne contribue pas non plus.

#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 / fenêtres anti-debug-référence

lire les sections 2 "PASE! NtGlobalFlags" et 2 "drapeaux Heap"

pense que cela peut l'expliquer ...


EDIT: solution ajoutée

dans votre gestionnaire pour CREATE_PROCESS_DEBUG_EVENT, ajoutez ce qui suit

// 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);

Ouais, WTF bien.

Vous savez que votre compilateur optimisera beaucoup de ces appels de fonction en les inline, puis optimiser le code là pour exclure tout ce qui ne fait quoi que ce soit, qui, dans le cas des vecteurs de int signifiera: à peu près pas beaucoup.

En mode débogage, inline n'est pas allumé car cela rendrait le débogage terrible.

Ceci est un bel exemple de la façon dont le code C ++ rapide peut vraiment être.

8 secondes ?? J'ai essayé le même en mode débogage. Pas plus d'une demi-seconde, je suppose. Êtes-vous sûr que ce sont les Destructeurs?

Pour votre information. Visual Studio 2008 SP1, Core 2 Duo 6700 CPU avec 2 Go de RAM.

n'a pas de sens pour moi -. Attacher un débogueur à un binaire aléatoire dans une configuration normale devrait pour la plupart seulement les interruptions piège de points d'arrêt (asm int 3, etc)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top