Globale Speicherverwaltung in C ++ in Stack oder Heap?


72

Wenn ich eine Datenstruktur in einer C ++ - Anwendung global deklariere, verbraucht sie Stapelspeicher oder Heapspeicher?

Zum Beispiel

struct AAA
{

.../.../.
../../..
}arr[59652323];

1
Was ist der Unterschied zwischen einer globalen Variablen und einer statischen Variablen (innerhalb einer Funktion)? Sie müssen für das Leben des Programms leben ...
user128026

stimmte zu, aber es ist ein Unterschied zwischen Zugänglichkeit
Sameer Karjatkar

@dspinozzi: Die Konstruktoren für globale Variablen werden vor main () aufgerufen, aber die Konstruktoren für statische Variablen werden beim ersten Aufruf der Funktion aufgerufen. Beide Arten von Variablen werden normalerweise in denselben Teilen des Speichers gespeichert - ich denke, GCC fügt sie in den Abschnitt .data ein.
Neil

Antworten:


137

Da ich mit den Antworten nicht zufrieden war und hoffe, dass derselbe Karjatkar mehr als nur eine einfache Ja / Nein-Antwort lernen möchte, können Sie loslegen.

In der Regel sind einem Prozess 5 verschiedene Speicherbereiche zugeordnet

  1. Code - Textsegment
  2. Initialisierte Daten - Datensegment
  3. Nicht initialisierte Daten - BSS-Segment
  4. Haufen
  5. Stapel

Wenn Sie wirklich erfahren möchten, was wo gespeichert ist, lesen Sie diese und setzen Sie ein Lesezeichen:

COMPILER, MONTAGE, LINKER UND LADER: EINE KURZE GESCHICHTE (siehe Tabelle w.5)

Anatomie eines Programms im Gedächtnis

Alt-Text


Bedeutet das, dass die nicht initialisierten Daten - bss und die initialisierten - Daten Teil des Heaps sind?
Sameer Karjatkar

Nein, sie sind kein Teil des Haufens, sie befinden sich in verschiedenen Bereichen, wie in meiner Antwort geschrieben wurde (die 5 verschiedenen Bereiche). Der Heap und der Stapel belegen den virtuellen Speicher über den Text- und Datensegmenten.
Mailand

8
Der wichtige Punkt ist, dass die bss- und Datensegmente beim ersten Laden des Programms in den Speicher zugewiesen werden und sich ihre Größe während der Ausführung nicht ändert. Im Gegensatz dazu ist der Inhalt des Heaps flüchtig und ändert sich während des Laufs, wenn dynamische Speicheroperationen ausgeführt werden.
Quark

3
Ich dachte, die Idee, den Stapel nach unten und den Heap nach oben wachsen zu lassen, war so, dass sie den verfügbaren Speicher in jedem Verhältnis nutzen können. Wird dies jedoch nicht durch das Laden der dynamischen Bibliotheken dazwischen verhindert?
Danijar

Geht die Initialisierung eines Zeigers auf NULL in das Daten- oder BSS-Segment? route_t* tblhead = NULL;
philx_x

28

Das Problem hier ist die Frage. Nehmen wir an, Sie haben ein winziges C-Programm (++, sie behandeln das genauso) wie folgt:

/* my.c */

char * str = "Your dog has fleas.";  /* 1 */
char * buf0 ;                         /* 2 */

int main(){
    char * str2 = "Don't make fun of my dog." ;  /* 3 */
    static char * str3 = str;         /* 4 */
    char * buf1 ;                     /* 5 */
    buf0 = malloc(BUFSIZ);            /* 6 */
    buf1 = malloc(BUFSIZ);            /* 7 */

    return 0;
}
  1. Dies ist weder auf dem Stapel NOR auf dem Heap zugeordnet. Stattdessen wird es als statische Daten zugewiesen und auf den meisten modernen Maschinen in ein eigenes Speichersegment gestellt. Die eigentliche Zeichenfolge wird auch als statische Daten zugewiesen und in richtig denkenden Maschinen in ein schreibgeschütztes Segment eingefügt.
  2. ist einfach ein statisch zugewiesener Zeiger; Platz für eine Adresse in statischen Daten.
  3. hat den Zeiger auf dem Stapel zugewiesen und wird bei der mainRückgabe effektiv freigegeben . Da es sich um eine Konstante handelt, wird die Zeichenfolge zusammen mit den anderen Zeichenfolgen im statischen Datenraum zugewiesen.
  4. wird tatsächlich genau wie bei 2 zugewiesen. Das staticSchlüsselwort gibt an, dass es nicht auf dem Stapel zugewiesen werden soll.
  5. ... aber buf1ist auf dem Stapel, und
  6. ... der malloc'ed Pufferraum ist auf dem Haufen.
  7. Übrigens versuchen Kinder das nicht zu Hause. mallochat einen Rückgabewert von Interesse; Sie sollten immer den Rückgabewert überprüfen.

Zum Beispiel:

char * bfr;
if((bfr = malloc(SIZE)) == NULL){
   /* malloc failed OMG */
   exit(-1);
}

Der malloced Pufferraum hat nichts mit globalen Variablen zu tun. Nur die Zeiger sind global. Bitte verwirren Sie die Leute nicht weiter.
EFraim

8
Oh, sei nicht albern. Der Fragesteller war sich eindeutig nicht sicher, was wohin ging, also schrieb ich eine Antwort, die darauf abzielte, sein Verständnis zu verbessern.
Charlie Martin

14

Normalerweise verbraucht es keine. Es wird versucht, sie in einem Speichersegment zuzuweisen, das für die Programmausführung wahrscheinlich eine konstante Größe hat. Es kann sich um BSS, Stack, Heap oder Daten handeln.


Durch Bearbeiten der Datei boot.ini können wir den virtuellen Speicher auf 3 GB erweitern. Wie weise gibt es eine Einstellung für das Speichersegment?
Sameer Karjatkar

Das wäre sinnlos, denn die Größe des statisch zugewiesenen Speichers kann sich nie ändern
Philippe Leybaert

6

Weder. Es ist .data Abschnitt.


Es hängt davon ab, ob der globale Speicher inline zugewiesen oder dynamisch aus der Anwendung zugewiesen wurde
Philippe Leybaert

1
Wenn ein Speicher dynamisch zugewiesen wurde, ist er nicht global (im Sinne einer globalen Variablen)
EFraim

Inwiefern ist es dann global, wenn es nicht im gesamten Programm enthalten ist?!
EFraim

2
@Philippe - Der Punkt ist, dass die Daten, auf die der globale Zeiger zeigt, nicht als global betrachtet werden können. Es kann sich sogar während der Programmausführung ändern (verschiedene Funktionen können den globalen Zeiger auf die gewünschte Stelle zurücksetzen)
EFraim

1
@Philippe: .data Abschnitte sind auch nicht nur .EXE.
EFraim

5

Der globale Speicher wird in einem festen Speicherblock oder auf dem Heap vorab zugewiesen, je nachdem, wie er von Ihrer Anwendung zugewiesen wird:

byte x[10]; // pre-allocated by the compiler in some fixed memory block
byte *y

main()
{
   y = malloc(10); // allocated on the heap
}

EDIT :

Die Frage ist verwirrend: Wenn ich eine Datenstruktur in einer C ++ - Anwendung global zuordne, verbraucht sie Stapelspeicher oder Heapspeicher?

"zuweisen"? Das könnte viele Dinge bedeuten, einschließlich des Aufrufs von malloc (). Es wäre anders gewesen, wenn die Frage lautete: "Wenn ich eine Datenstruktur global deklariere und initialisiere".

Vor vielen Jahren, als CPUs noch 64K-Segmente verwendeten, waren einige Compiler intelligent genug, um dynamisch Speicher vom Heap zuzuweisen, anstatt einen Block im .data-Segment zu reservieren (aufgrund von Einschränkungen in der Speicherarchitektur).

Ich denke ich bin einfach zu alt ....


Es heißt "auf dem Haufen zugeteilt" und das ist ziemlich richtig. Sofern diese Frage nicht als "Anfänger" oder "Anfänger" gekennzeichnet ist, sollte dies eine ausreichende Erinnerung an das Geschehen sein.
Don Johe

@Don: Nein. Das globale Ding ist der Zeiger und nicht der Speicher, auf den es zeigt. Sie können den Speicher so behandeln, wie Sie möchten. Es ist auch nicht da, um den ganzen Lauf zu bleiben. Sie können es manchmal sogar auf einen Stapel richten.
EFraim

1
Wenn daraus eine Lektion zu lernen ist, sollten Sie vermeiden, Fragen zu beantworten, bei denen die genaue Bedeutung der Frage unklar ist. Meine Antwort ist nicht falsch, es ist nur so, dass einige Leute denken, dass ihre Interpretation eines Wortes ausreicht, um alles abzustimmen, was ihre Ansicht nicht unterstützt. Selbst jetzt, 10 Stunden nachdem die Frage gestellt wurde, ist immer noch nicht klar, was das OP bedeutete.
Philippe Leybaert

Ja, das ist mein Fehler bei der Formulierung der Frage. Ich habe es jetzt bearbeitet
sameer karjatkar

4

Weder das globale Deklarieren einer Datenstruktur in C ++ verbraucht Heap- noch Stack-Speicher. Tatsächlich werden globale Variablen normalerweise in einem Datensegment zugewiesen, dessen Größe während des gesamten Programms unverändert bleibt. Stapel und Heaps werden normalerweise für Variablen verwendet, die während der Ausführung des Programms erstellt und zerstört werden.

Speicherplatz programmieren


0

Das globale Objekt selbst belegt Speicher, den die Laufzeit oder der Compiler für ihn reserviert, bevor main ausgeführt wird. Dies sind keine variablen Laufzeitkosten, also weder Stapel noch Heap.

Wenn der ctor des Objekts Speicher zuweist, befindet er sich im Heap, und alle nachfolgenden Zuweisungen durch das Objekt sind Heap-Zuweisungen.

Es hängt von der genauen Art des globalen Objekts ab, ob es sich um einen Zeiger oder um das gesamte Objekt selbst handelt, das global ist.


-1

Globale Variablen leben auf dem Heap. Dies ist ein Sonderfall, weil sie für das Leben des Programms leben


-3

Wenn Sie den Speicher explizit selbst durch new oder malloc zuweisen, wird er im Heap zugewiesen. Wenn der Compiler den Speicher zuweist, wird er auf dem Stapel zugewiesen.


Der globale Speicher wird niemals auf dem Stapel zugewiesen. Der Stapel wird nur für lokale Variablen und Parameter verwendet
Philippe Leybaert

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.