Determinazione dello spazio dello stack con Visual Studio

Sto programmando in C in Visual Studio 2005. Ho un programma multi-thread, ma non è particolarmente importante qui.

Come posso determinare (approssimativamente) la quantità di spazio occupato dai miei thread?

La tecnica che stavo progettando di utilizzare è impostare la memoria dello stack su un valore predeterminato, ad esempio 0xDEADBEEF, eseguire il programma per un lungo periodo, mettere in pausa il programma e indagare sullo stack.

Come leggo e scrivo la memoria dello stack con Visual Studio?

EDIT: vedere, ad esempio, “Come determinare l’utilizzo massimo dello stack”. Questa domanda parla di un sistema embedded, ma qui sto cercando di determinare la risposta su un normale PC.

Windows non commette immediatamente la memoria dello stack; al contrario, riserva lo spazio degli indirizzi e lo impegna pagina per pagina al momento dell’accesso. Leggi questa pagina per maggiori informazioni.

Di conseguenza, lo spazio degli indirizzi dello stack è costituito da tre aree contigue:

  • Memoria riservata ma non salvata che può essere utilizzata per la crescita dello stack (ma non è mai stata ancora utilizzata);
  • Pagina di guardia, a cui non è mai stato ancora accesso, e serve per innescare la crescita dello stack quando si accede;
  • Memoria impegnata, ovvero memoria dello stack a cui il thread ha mai avuto accesso.

Questo ci permette di build una funzione che ottiene le dimensioni dello stack (con granularità delle dimensioni della pagina):

static size_t GetStackUsage() { MEMORY_BASIC_INFORMATION mbi; VirtualQuery(&mbi, &mbi, sizeof(mbi)); // now mbi.AllocationBase = reserved stack memory base address VirtualQuery(mbi.AllocationBase, &mbi, sizeof(mbi)); // now (mbi.BaseAddress, mbi.RegionSize) describe reserved (uncommitted) portion of the stack // skip it VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // now (mbi.BaseAddress, mbi.RegionSize) describe the guard page // skip it VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // now (mbi.BaseAddress, mbi.RegionSize) describe the committed (ie accessed) portion of the stack return mbi.RegionSize; } 

Una cosa da considerare: CreateThread consente di specificare le dimensioni iniziali del commit dello stack (tramite il parametro dwStackSize , quando il flag STACK_SIZE_PARAM_IS_A_RESERVATION non è impostato). Se questo parametro è diverso da zero, la nostra funzione restituirà il valore corretto solo quando l’utilizzo dello stack diventa maggiore del valore dwStackSize .

È ansible utilizzare le informazioni nel blocco informazioni thread Win32

Quando vuoi inserire un thread per scoprire quanto spazio di stack utilizza puoi fare qualcosa del genere:

 #include  #include  #include  inline NT_TIB* getTib() { return (NT_TIB*)__readfsdword( 0x18 ); } inline size_t get_allocated_stack_size() { return (size_t)getTib()->StackBase - (size_t)getTib()->StackLimit; } void somewhere_in_your_thread() { // ... size_t sp_value = 0; _asm { mov [sp_value], esp } size_t used_stack_size = (size_t)getTib()->StackBase - sp_value; printf("Number of bytes on stack used by this thread: %u\n", used_stack_size); printf("Number of allocated bytes on stack for this thread : %u\n", get_allocated_stack_size()); // ... } 

Lo stack non funziona come te lo aspetti. Lo stack è una sequenza lineare di pagine, l’ultima (in alto) una delle quali è contrassegnata da un bit di page guard. Quando questa pagina viene toccata, il bit di guardia viene rimosso e la pagina può essere utilizzata. Per ulteriore crescita, viene assegnata una nuova pagina di guardia.

Quindi, la risposta che si desidera è dove viene assegnata la pagina di prova. Ma la tecnica che proponi toccherebbe la pagina in questione e, di conseguenza, invaliderebbe la cosa che stai cercando di misurare.

Il modo non invasivo per determinare se una pagina (stack) ha il bit di guardia è tramite VirtualQuery() .

È ansible utilizzare la funzione GetThreadContext () per determinare il puntatore dello stack corrente del thread. Quindi utilizzare VirtualQuery () per trovare la base dello stack per questo puntatore. La sottrazione di questi due puntatori ti darà la dimensione dello stack per il thread specificato.