Frage

Ich verwende MinGW mit GCC 3.4.5 (mingw-special vista r3).

Da meine C-Anwendung viel Stapel verbraucht, habe ich mich gefragt, ob es eine Möglichkeit gibt, programmgesteuert festzustellen, wie viel Stapel übrig bleibt, damit ich die Situation sauber bewältigen kann, wenn ich merke, dass mir bald der Stapel ausgeht.

Wenn nicht, wie würden Sie sonst das Problem umgehen, dass möglicherweise nicht mehr genügend Stapelspeicher vorhanden ist?

Ich habe keine Ahnung, mit welcher Stapelgröße ich beginnen werde, also müsste ich das auch programmgesteuert identifizieren.

War es hilfreich?

Lösung

Raymond Chen (The Old New Thing), hat eine gute Antwort auf diese Frage:

Wenn Sie Fragen haben, sind Sie wahrscheinlich etwas falsch machen.

Hier einige Win32-details auf stack-Zuweisung: MSDN.

Wenn Sie denken, Sie könnten begrenzt werden, die von stack-Speicher, werden Sie fast sicher sein, begrenzt durch den verfügbaren virtuellen Speicher, in diesem Fall, Sie müssen zu finden eine andere Lösung.

Was genau versuchst du zu tun?

Andere Tipps

Die getrusage-Funktion wird Ihnen die aktuelle Auslastung .(siehe man getrusage).

Die getrlimit in Linux würde helfen, Holen die stack-Größe, die mit der RLIMIT_STACK parameter.

#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);
}

Bitte geben Sie einen Blick auf man getrlimit.Die gleichen Informationen können abgerufen werden, indem ulimit -s oder ulimit -a stack-Größe-Zeile.Auch haben Sie einen Blick auf setrlimit Funktion die es erlauben würde, um die Grenzen.Aber wie die genannten in den anderen Antworten, wenn Sie anpassen müssen stack dann wahrscheinlich sollten Sie erneut prüfen, Ihr design.Wenn Sie wollen eine große Auswahl, warum nicht nehmen Sie den Speicher aus dem heap ?

Unter der Adresse einer lokalen Variablen aus dem Stapel arbeiten würde.Dann in einer mehr verschachtelter Aufruf können Sie subtrahieren die Adresse eines anderen lokalen zu finden, der Unterschied zwischen Ihnen

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;
} 

Wenn Sie den code ist multi-threaded, dann müssen Sie beschäftigen sich mit der Speicherung der top_of_stack variable auf eine pro-thread-basis.

überprüfen Sie, ob Ihr compiler unterstützt stackavail()

Vorausgesetzt, Sie wissen, die Größe der volle Stapel könnte Sie wahrscheinlich fügen Sie einige Assembler-code zu Lesen, ESP.
Wenn Sie Lesen, ESP und speichern Sie es beiseite in die main-Funktion, können Sie vergleichen die aktuelle ESP-des ESP-Sie haben in der Haupt-und sehen Sie, wieviel ESP hat sich geändert.Das gibt Ihnen einen Hinweis darauf, wie viel Stapel, den Sie gewohnt sind.

Dies ist ein problem, das ich habe aufgegeben.Mit viel hacking und (meist) zu beten, Sie können erhalten eine Lösung, die zu einem bestimmten Zeitpunkt an einem bestimmten Computer.Aber im Allgemeinen scheint es keinen guten Weg, dies zu tun.

Sie müssen erhalten Sie die stack-position und Größe von außerhalb Ihres Programms (auf Linux-man könnte es aus /proc/<pid>/maps).In Ihrem Programm müssen Sie irgendwie testen, wo Sie auf den Stapel.Mit lokalen Variablen ist möglich, aber es gibt keine wirkliche Garantie, dass Sie tatsächlich auf dem stack.Sie können auch versuchen, den Wert aus dem stack-pointer-register mit einige Montage.

So, jetzt haben Sie den Speicherort der Stapel, Ihre Größe und die aktuelle position, und Sie nehme an, Sie wissen, in welche Richtung der Stapel wächst.Wann gehen Sie in der stack-overflow-Modus?Sie besser nicht tun es in der Nähe der Ende, weil Ihre Schätzung (d.h.Adresse der lokalen variable oder ein Wert vom stack pointer) ist wahrscheinlich ein bisschen zu optimistisch ist;es ist nicht ungewöhnlich, Adresse Speicher über den stack-pointer.Auch Sie haben keine Ahnung, wie viel Platz auf dem Stapel jeder gegebenen Funktion (und die Funktionen, die es aufruft) benötigen.So müssen Sie verlassen einige Raum am Ende.

Ich kann nur Ratschläge, die Sie nicht tun Holen Sie sich in diesem Chaos, und versuchen zu vermeiden, sehr Tiefe der Rekursion.Möglicherweise möchten Sie auch steigern Sie Ihre stack-Größe;unter Windows müssen Sie kompilieren diese in die ausführbare Datei, glaube ich.

Für windows:Ich habe dies getan, bevor mit dem VirtualQuery Funktion von Kernel32.dll.Ich habe nur ein Beispiel in C#, aber es demonstriert die Technik:

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:Dieser code kann auch auf StackOverflow auf eine andere Frage, die ich fragte, Wann ich war versucht zu reparieren, einen Fehler im code: Arithmetische operation führte zu einem überlauf in unsicheren C#geben Sie den link-Beschreibung hier

vielleicht hilft es für die Windows-Plattform nur:

in den PE-header (IMAGE_NT_HEADERS) von der exe-Datei es gibt einige Aufzeichnungen wie:

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;
    ...
}

Es ist ein einfacher Weg, um diese Werte abzurufen:mit GetModuleHandle(NULL), wird geben Sie die imagebase (Griff) des Moduls, Adresse, wo Sie finden eine IMAGE_DOS_HEADER Struktur, die wird helfen Sie zu finden die IMAGE_NT_HEADERS Struktur (imagebase+IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS, und dort finden Sie die Felder: SizeOfStackReserve und SizeOfStackCommit.

Der maximale Betrag, der Platz, den die OS-Zuordnung für dein stack ist SizeOfStackReserve.

Wenn Sie erwägen, versuchen, lassen Sie es mich wissen und ich helfen Ihnen gerne weiter.Es ist ein Weg, um die Größe des Stapels in einem bestimmten Punkt.

Auf Linux-rufen Sie getrusage und prüfen die zurückgegebenen struct rusage s ru_isrss Mitglied (integral unshared stack size).

Von der MINGW-Website und Ihrer sourceforge-site-tracking-patches, sehe ich, dass im Mai 2008 gab es einige Flicken getan, um getrusage und wie es aussieht ist es in der Regel unterstützt eine ganze Weile.Sie sollten sorgfältig prüfen, die für jede Einschränkungen in Bezug darauf, wie viel der typische Linux-Funktionalität wird unterstützt durch MinGW.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top