2012-08-27 10 views
6

Ich möchte genau verstehen, wo die globalen Variablen in meinem Programm gespeichert sind. Auf dem Stapel? Auf dem Haufen? Irgendwo anders?Globale Variable scheint keinen Speicherplatz zu belegen

dafür Also schrieb ich diesen kleinen Code:

int global_vector[1000000]; 
int main() { 
    global_vector[0] = 1; // just to avoid a compilation warning 
    while(true); // to give me time to check the amount of RAM used by my program 
    return 0; 
} 

Egal wie groß ich global_vector machen, verwendet das Programm nur eine wirklich winzige Menge an RAM. Ich verstehe den Grund dafür nicht. Könnte jemand bitte erklären?

+5

Ich bezweifle, dass dies relevant ist, da es ein statisches Array ist, aber haben Sie versucht, das gesamte Array auf Null zu setzen? – Mysticial

+2

Eigentlich ist das völlig relevant.Mit 'memset' ging das Programm von 92K auf 381.6M über. –

+0

In diesem Fall ist die Antwort von templatetypedef korrekt. – Mysticial

Antwort

11

Dies ist vollständig implementierungsabhängig, aber in der Regel werden globale Variablen in einem speziellen Speichersegment gespeichert, das vom Stapel und vom Heap getrennt ist. Dieser Speicher könnte als Puffer mit fester Größe innerhalb der ausführbaren Datei selbst oder in einem Segment zugewiesen werden, das dem Programm beim Start vom Betriebssystem übergeben wird.

Der Grund, warum die Speicherauslastung nicht steigt, hängt wahrscheinlich damit zusammen, wie der virtuelle Speicher vom Betriebssystem gehandhabt wird. Als eine Optimierung gibt das Betriebssystem dem Programm für dieses riesige Array tatsächlich keinen Speicher, es sei denn, Sie verwenden es tatsächlich. Versuchen Sie, Ihr Programm auf for-loop über den gesamten Inhalt des Arrays zu ändern, und prüfen Sie, ob dadurch die RAM-Auslastung steigt. (Es ist auch möglich, dass der Optimierer in Ihrem Compiler das gigantische Array eliminiert, da es fast vollständig unbenutzt ist. Das Setzen einer Schleife, um alle Werte zu lesen/schreiben, könnte auch den Compiler dazu zwingen, es zu behalten).

Hoffe, das hilft!

+0

Genau. Nach dem Vorschlag von Mysticial habe ich 'memset' verwendet, um alle Array-Werte auf Null zu setzen und dadurch die RAM-Speicherauslastung dramatisch zu erhöhen. –

+0

Die Tatsache, dass ein ** globales ** Array "fast" unbenutzt ist, ist irrelevant ... der * Compiler * kann normalerweise keine globalen Optimierungen durchführen. Es gibt hier eine Ausnahme, weil es "main" ist und vor der Verwendung des Arrays zurückkehrt, so dass kein Code in anderen Kompilierungseinheiten es verwenden kann. Eine solche Optimierung ist jedoch sinnlos. –

5

Der Optimierer entfernt das Array wahrscheinlich vollständig, da Sie es nie verwenden.

+1

Aber ich tat. Was ist mit der ersten Zeile nach 'int main()'? –

+0

@ Krümmung: Sie haben nur ein Element verwendet, niemals die Leistung des Optimierers unterschätzen habe nicht wirklich überprüft) – SLaks

+2

@curvature Was du getan hast hat keinen beobachtbaren Effekt, also könnte der Compiler es entfernen. – ollb

3

Globale Variablen, die keine expliziten Initialisierer erhalten, wie in diesem Fall Ihre, werden standardmäßig auf 0 initialisiert. Sie werden in einen Speicherbereich mit der Bezeichnung .bss segment gestellt, und in der Objektdatei/ausführbaren Datei werden keine zusätzlichen Daten gespeichert, die den Anfangswert der Daten angeben (im Gegensatz zu explizit initialisierten Daten, deren Anfangswert irgendwo gespeichert werden muss).

Wenn das Betriebssystem das Programm lädt, liest es die Beschreibungen aller Segmente ein und weist Speicher dafür zu. Da es weiß, dass das .bss-Segment für alle Nullen initialisiert wird, kann es einen hinterhältigen Trick machen, um zu vermeiden, dass tatsächlich Tonnen von Speicher zugewiesen und dann für alle Nullen initialisiert werden müssen: Adressraum für das Segment auf der Prozessseite Tabelle, aber alle Seiten zeigen auf die gleiche Seite, gefüllt mit Nullen.

Diese einzelne Nullseite ist ebenfalls schreibgeschützt. Wenn dann und wenn der Prozess in einige Daten in dem BSS-Segment schreibt, tritt ein Seitenfehler auf. Das Betriebssystem fängt den Seitenfehler ab, ermittelt, was passiert, und weist dann tatsächlich einen eindeutigen Speicher für diese Datenseite zu. Dann startet es den Befehl neu, und der Code fährt auf seinem fröhlichen Weg fort, als ob der Speicher die ganze Zeit zugewiesen worden wäre.

Also, das Endergebnis ist, dass, wenn Sie eine globale Variable oder Array mit Null initialisiert haben, jeder Seitengröße Daten (in der Regel 4 KB), nie geschrieben wird nie tatsächlich Speicher für sie zugewiesen haben.

Hinweis: Ich bin ein wenig verschwommen hier mit dem Wort "zugewiesen". Wenn Sie sich mit so etwas beschäftigen, werden Sie wahrscheinlich Wörter wie "reserviert" und "engagiert" finden. Weitere Informationen zu diesen Begriffen im Kontext von Windows finden Sie unter this question und this page.