Der folgende Code gibt mir einen Segmentierungsfehler, wenn er auf einem 2-GB-Computer ausgeführt wird, funktioniert aber auf einem 4-GB-Computer.
int main()
{
int c[1000000];
cout << "done\n";
return 0;
}
Die Größe des Arrays beträgt nur 4 MB. Gibt es eine Begrenzung für die Größe eines Arrays, das in C++ verwendet werden kann?
Karl Salvia
Wahrscheinlich bekommen Sie hier nur einen Stapelüberlauf. Das Array ist zu groß, um in den Stapelbereich Ihres Programms zu passen; Die Stack-Wachstumsgrenze beträgt normalerweise 8 MiB oder 1 MiB für User-Space-Code auf den meisten Mainstream-Desktop-/Server-Betriebssystemen. (Normale C++-Implementierungen verwenden den asm-Stack für die automatische Speicherung, dh nicht-static lokale Variablen-Arrays. Dadurch wird die Zuweisung kostenlos aufgehoben, wenn Funktionen zurückkehren oder eine Ausnahme durch sie weitergegeben wird.)
Wenn Sie das Array dynamisch zuweisen, sollten Sie in Ordnung sein, vorausgesetzt, Ihr Computer verfügt über genügend Speicher.
int* array = new int[1000000]; // may throw std::bad_alloc
Aber denken Sie daran, dass dies von Ihnen verlangt wird delete[] das Array manuell, um Speicherlecks zu vermeiden, selbst wenn Ihre Funktion über eine Ausnahme beendet wird. Von manuellem Neuen/Löschen wird in modernem C++ dringend abgeraten, lieber RAII.
Eine bessere Lösung wäre zu verwenden std::vector<int> array (cpReferenz). Sie können Platz für 1000000 Elemente reservieren, wenn Sie wissen, wie groß es werden wird. Oder auch resize es, sie standardmäßig zu konstruieren (dh den Speicher mit Null zu initialisieren, anders als wenn Sie ein einfaches Array im C-Stil ohne Initialisierer deklarieren), wie std::vector<int> array(1000000)
Wenn das std::vector Wenn ein Objekt den Gültigkeitsbereich verlässt, wird sein Destruktor den Speicher für Sie freigeben, selbst wenn dies über eine Ausnahme in einer untergeordneten Funktion geschieht, die von einer übergeordneten Funktion abgefangen wird.
Danke für die Antwort, aber könnten Sie mir erklären, warum Arrays auf dem Stapel zugewiesen werden und warum nicht im Hauptprogrammspeicher.
– Mayank
4. Dezember 2009 um 15:51 Uhr
Der angegebene Code wird auf dem Stapel zugewiesen, da er zur Kompilierzeit als Array mit einer konstanten Anzahl von Elementen angegeben wird. Werte werden nur mit malloc, new usw. auf den Heap gelegt.
– Seth Johnson
4. Dezember 2009 um 16:05 Uhr
Alle automatischen Variablen werden auf dem Stack allokiert. Wenn Sie sich das Disasseble ansehen, sehen Sie die Größe Ihrer lokalen Variablen, die vom Stapelzeiger abgezogen werden. Wenn Sie malloc oder calloc oder eine der Speicherfunktionen aufrufen, suchen die Funktionen nach Speicherblöcken, die groß genug sind, um Ihre Anforderung zu erfüllen.
– wiederholen
4. Dezember 2009 um 16:12 Uhr
@Charles, warum könnten wir mehr Speicher vom Heap zuweisen, nicht vom Stack? Nach meinem Verständnis bewegen sich sowohl Stack als auch Heap im zugewiesenen Adressraum im Speicher in entgegengesetzte Richtung.
– Saurabh-Agarwal
24. Februar 2015 um 6:58 Uhr
@saurabhagarwal Der Haufen bewegt sich nicht. Es ist nicht einmal eine zusammenhängende Speicherregion. Der Zuordner gibt einfach einen freien Speicherblock zurück, der Ihrer Größenanforderung entspricht. Was und wo sind Stack und Heap?
– phuklv
23. Juni 2015 um 4:45 Uhr
Günther Piez
In C oder C++ werden lokale Objekte normalerweise auf dem Stack allokiert. Sie weisen dem Stapel ein großes Array zu, mehr als der Stapel verarbeiten kann, sodass Sie einen Stapelüberlauf erhalten.
Weisen Sie es nicht lokal auf dem Stack zu, sondern verwenden Sie stattdessen einen anderen Ort. Dies kann erreicht werden, indem entweder das Objekt hergestellt wird global oder es global zuordnen Haufen. Globale Variablen sind in Ordnung, wenn Sie die von keiner anderen Kompilationseinheit verwenden. Um sicherzustellen, dass dies nicht versehentlich passiert, fügen Sie einen statischen Speicherbezeichner hinzu, andernfalls verwenden Sie einfach den Heap.
Dadurch wird das BSS-Segment zugewiesen, das Teil des Heaps ist. Da es sich im statischen Speicher befindet, wird es mit Null initialisiert, wenn Sie nichts anderes angeben, im Gegensatz zu lokalen Variablen (automatischer Speicher) einschließlich Arrays.
static int c[1000000];
int main()
{
cout << "done\n";
return 0;
}
Ein Nicht-Null-Initialisierer bewirkt, dass ein Compiler im DATA-Segment zuweist, das ebenfalls Teil des Heaps ist. (Und alle Daten für den Array-Initialisierer nehmen Platz in der ausführbaren Datei ein, einschließlich aller impliziten nachgestellten Nullen, anstatt nur eine Größe für Zero-Init im BSS)
int c[1000000] = {1, 2, 3};
int main()
{
cout << "done\n";
return 0;
}
Dadurch wird an einer nicht angegebenen Stelle im Heap zugewiesen:
int main()
{
int* c = new int[1000000]; // size can be a variable, unlike with static storage
cout << "done\n";
delete[] c; // dynamic storage needs manual freeing
return 0;
}
Wenn Sie das dritte Muster verwenden und auf dem Heap zuweisen, vergessen Sie nicht, zu löschen[] den Zeiger irgendwann, oder Sie werden Speicher verlieren. Oder schauen Sie sich intelligente Hinweise an.
– davidA
5. September 2012 um 1:20 Uhr
@meowsqueak Natürlich ist es eine gute Übung delete überall, wo Sie mit zuweisen new. Aber wenn Sie sicher sind, dass Sie Speicher nur einmal zuweisen (wie in main), ist dies streng genommen nicht erforderlich – der Speicher wird garantiert beim Beenden von main freigegeben, auch ohne explizit delete.
– Günther Piez
5. September 2012 um 8:11 Uhr
‘at’drhirsch (wie macht man überhaupt ein at-Zeichen?) – ja, fairer Kommentar. Da das OP neu in der Sprache erscheint, wollte ich nur sicherstellen, dass sie und alle anderen, die Ihre gute Antwort sehen, sich der Auswirkungen der dritten Option bewusst sind, wenn sie allgemein verwendet werden.
– davidA
5. September 2012 um 12:19 Uhr
RSFalcon7
Wenn Sie die meisten UNIX- und Linux-Systeme verwenden, können Sie die Stack-Größe mit dem folgenden Befehl vorübergehend erhöhen:
ulimit -s unlimited
Aber sei vorsichtig, das Gedächtnis ist eine begrenzte Ressource und mit großer Macht kommen große Verantwortungen 🙂
Dies ist die Lösung, aber ich rate allen, beim Entfernen dieser Standardbeschränkungen für die Stapelgröße des Programms äußerst vorsichtig zu sein. Sie werden nicht nur einen starken Leistungsabfall erleben, sondern Ihr System kann abstürzen. Zum Beispiel habe ich versucht, ein Array mit 16 000 000 Integer-Elementen mit Quicksort auf einer Maschine mit 4 GB RAM zu sortieren, und mein System wurde fast zerstört. lol
– rbaleksandar
16. Oktober 2014 um 16:51 Uhr
@rbaleksandar Ich denke, Sie ~ 16 MB Programm töten fast Ihren Computer, weil Sie mit mehreren Kopien des Arrays gearbeitet haben (möglicherweise eine pro Funktionsaufruf?) Versuchen Sie eine speicherbewusstere Implementierung;)
– RSFalcon7
16. Oktober 2014 um 23:20 Uhr
Ich bin mir ziemlich sicher, dass die Array-Behandlung in Ordnung ist, da ich als Referenz und nicht als Wert übergebe. Das gleiche passiert mit Bubblesort. Zur Hölle, auch wenn meine Implementierung von Quicksort scheiße ist, Bubblesort ist etwas, das Sie unmöglich falsch implementieren können. lol
– rbaleksandar
17. Oktober 2014 um 10:07 Uhr
LOL, du könntest Radix Sort ausprobieren oder einfach std::sort verwenden 🙂
– RSFalcon7
17. Oktober 2014 um 16:54 Uhr
Keine Chance. Es ist eine Laboraufgabe. 😀
– rbaleksandar
17. Oktober 2014 um 17:00 Uhr
Ihr Array wird auf dem Stapel zugewiesen. Versuchen Sie in diesem Fall, ein Array derselben Größe mit alloc zuzuweisen.
Narek
Weil Sie das Array im Stack speichern. Sie sollten es auf dem Haufen lagern. Sehen dieser Link das Konzept des Haufens und des Stacks zu verstehen.
Arti
Ihr einfaches Array wird im Stapel zugewiesen, und der Stapel ist auf wenige Magabyte begrenzt, daher bekommt Ihr Programm einen Stapelüberlauf und stürzt ab.
Wahrscheinlich ist es am besten, heap-allocated zu verwenden std::Vektor-basiertes Array, das anstelle Ihres einfachen Arrays fast auf die Größe des gesamten Speichers wachsen kann.
Im obigen Beispiel erhalten Sie fast das gleiche Verhalten, als ob Sie ein einfaches Array zugewiesen hätten int c[100][456][123]; (mit der Ausnahme, dass der Vektor auf dem Heap statt auf dem Stack zuweist), können Sie auf Elemente zugreifen als c[10][20][30] wie im einfachen Array. Dieses obige Beispiel weist auch Arrays auf dem Heap zu, was bedeutet, dass Sie Arraygrößen bis zur gesamten Speichergröße haben können und nicht durch die Stapelgröße begrenzt sind.
Um den Zeiger auf das erste Element im Vektor zu erhalten, verwenden Sie &c[0] oder nur c.data().
Es kann noch einen Weg geben, der für mich funktioniert hat! Sie können die Größe des Arrays reduzieren, indem Sie seinen Datentyp ändern:
int main()
{
short c[1000000];
cout << "done\n";
return 0;
}
oder
int main()
{
unsigned short c[1000000];
cout << "done\n";
return 0;
}
10027200cookie-checkSegmentierungsfehler bei großen Arraysyes