Domanda

Sto usando MinGW con GCC 3.4.5 (mingw-speciale vista r3).

Il mio C applicazione utilizza un sacco di stack quindi mi chiedevo c'è un modo che io posso dire a livello di programmazione quanto stack rimanente, così posso gestire correttamente la situazione se vedo che sto per uscire.

Se non che in altri modi sarebbe risolvere il problema della potenzialmente in esecuzione di spazio di stack?

Non ho idea di che cosa dimensione dello stack inizierò con così avrebbe bisogno di identificare che anche a livello di programmazione.

È stato utile?

Soluzione

Raymond Chen (The Old New Thing) è una buona risposta a questa domanda:

Se hai da chiedere, probabilmente stai facendo qualcosa di sbagliato.

Ecco alcune Win32 dettagli su allocazione dello stack: MSDN.

Se pensi di essere limitato da spazio di stack, quasi certamente essere limitato dalla memoria virtuale disponibile, nel qual caso, sarà necessario trovare una soluzione diversa.

Che cosa stai cercando di fare?

Altri suggerimenti

Il getrusage funzione si ottiene l'uso corrente .(vedere man getrusage).

Il getrlimit in Linux aiutare a recuperare la dimensione dello stack con il RLIMIT_STACK parametro.

#include <sys/resource.h>
int main (void)
{
  struct rlimit limit;

  getrlimit (RLIMIT_STACK, &limit);
  printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max);
}

Si prega di dare un'occhiata a man getrlimit.Le stesse informazioni possono essere recuperati da ulimit -s o ulimit -a la dimensione dello stack di riga.Anche un'occhiata a setrlimit funzione che permette di impostare i limiti.Ma come i citati nelle altre risposte se è necessario regolare stack allora probabilmente è necessario prendere in considerazione il vostro disegno.Se si desidera una grande matrice perché non prendere la memoria heap ?

Prendendo l'indirizzo di una variabile locale off nello stack di lavoro.Quindi in un più nidificati chiamata si può sottrarre l'indirizzo di un altro locale per trovare la differenza tra di loro

size_t top_of_stack;

void Main()
{
  int x=0;
  top_of_stack = (size_t) &x;

  do_something_very_recursive(....)
}

size_t SizeOfStack()
{
  int x=0;
  return top_of_stack - (size_t) &x;
} 

Se il codice è multi-threaded, allora avete bisogno di trattare con l'archiviazione il top_of_stack variabile in base al thread.

controllare se il tuo compilatore supporta stackavail()

Supponendo che si conosce la dimensione dello stack completo probabilmente si potrebbe aggiungere un po ' di assemblaggio di codice per leggere ESP.
Se leggi l'ESP e salvarlo da parte del principale funzione, è possibile confrontare l'attuale ESP per l'ESP si hanno in principale e vedere quanto l'ESP è cambiato.Che vi darà un'indicazione di quanto stack sei abituato.

Questo è un problema che ho rinunciato.Con un sacco di hacking e (soprattutto) di pregare, è possibile ottenere una soluzione che funziona in un dato momento in un dato macchina.Ma in generale sembra che ci sia alcun modo decente per fare questo.

Dovrete ottenere lo stack, posizione e dimensione al di fuori del vostro programma (su Linux si potrebbe ottenere da /proc/<pid>/maps).Nel programma si deve in qualche modo la prova in cui si è in pila.Utilizzo di variabili locali è possibile, ma non vi è alcuna garanzia reale che essi sono in realtà in pila.Si può anche provare a ottenere il valore dello stack pointer con un po ' di assemblaggio.

Così ora avete la località di pila, la sua dimensione e la posizione corrente e si supponga di sapere in quale direzione lo stack cresce.Quando vai in stack-overflow modalità?È meglio non farlo vicino alla fine, perché la tua stima (es.l'indirizzo della variabile locale o il valore in cima allo stack pointer) è forse un po ' troppo ottimista;non è raro indirizzo di memoria al di là del puntatore dello stack.Inoltre non hai idea di quanto spazio sullo stack una data funzione (e le funzioni che le chiamate) bisogno.Quindi dovrete lasciare un bel po ' di spazio alla fine.

Posso solo consigliarvi di non fare entrare in questo pasticcio e cercare di evitare di profondità di ricorsione.Si potrebbe anche voler aumentare la vostra dimensione dello stack;su Windows devi compilare questo codice eseguibile, credo.

Per windows:Ho fatto questo prima di utilizzare il VirtualQuery funzione da Kernel32.dll.Ho solo un esempio in C# ma dimostra la tecnica:

public static class StackManagement
    {
        [StructLayout(LayoutKind.Sequential)]
        struct MEMORY_BASIC_INFORMATION
        {
            public UIntPtr BaseAddress;
            public UIntPtr AllocationBase;
            public uint AllocationProtect;
            public UIntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        };

        private const long STACK_RESERVED_SPACE = 4096 * 16;

        public unsafe static bool CheckForSufficientStack(UInt64 bytes)
        {
            MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
            UIntPtr currentAddr = new UIntPtr(&stackInfo);
            VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

            UInt64 stackBytesLeft = currentAddr.ToUInt64() - stackInfo.AllocationBase.ToUInt64();

            return stackBytesLeft > (bytes + STACK_RESERVED_SPACE);
        }

        [DllImport("kernel32.dll")]
        private static extern int VirtualQuery(UIntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
    }

BTW:Questo codice può anche essere trovato su StackOverflow su un'altra domanda che ho chiesto quando stavo cercando di risolvere un bug nel codice: Operazione aritmetica ha provocato un overflow pericolosi di C#inserire descrizione del link qui

forse questo sarà di aiuto solo per la piattaforma Windows:

nell'intestazione PE (IMAGE_NT_HEADERS) del tuo exe ci sono alcuni record come:

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    ...
}

C'è un modo semplice per ottenere questi valori:utilizzando GetModuleHandle(NULL) darà il imagebase (manico) del modulo, l'indirizzo dove troverete un IMAGE_DOS_HEADER struttura che vi aiuterà a trovare il IMAGE_NT_HEADERS struttura (imagebase+IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS, dove si trovano i campi: SizeOfStackReserve e SizeOfStackCommit.

La quantità massima di spazio che il sistema operativo consente di allocare per il vostro stack è SizeOfStackReserve.

Se si considera che cercano questo, fatemelo sapere e io vi sosterrò.C'è un modo per ottenere la dimensione dello stack utilizzato in un certo punto.

Su Linux, si sarebbe chiamata getrusage e controllare il restituiti struct rusage s ru_isrss membro (integrale annullata la dimensione dello stack).

Da MINGW sito e la sua sourceforge di monitoraggio del sito di patch, vedo che nel Maggio del 2008 c'era qualche patch fa intorno getrusage e sembra che è stato generalmente sostenuto per un po'.Si dovrebbe controllare attentamente per eventuali avvertenze in termini di quantità che di Linux tipica funzionalità è supportata da MinGW.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top