Errore di segmentazione su array di grandi dimensioni


116

Il codice seguente mi dà un errore di segmentazione quando viene eseguito su una macchina da 2 GB, ma funziona su una macchina da 4 GB.

int main()
{
   int c[1000000];
   cout << "done\n";
   return 0;
}

La dimensione dell'array è di soli 4 Mb. C'è un limite alla dimensione di un array che può essere utilizzato in c ++?

Risposte:


130

Probabilmente stai solo ottenendo un overflow dello stack qui. L'array è troppo grande per adattarsi allo spazio degli indirizzi dello stack del programma.

Se allochi l'array sull'heap, dovresti stare bene, supponendo che la tua macchina abbia abbastanza memoria.

int* array = new int[1000000];

Ma ricorda che questo richiederà delete[]l'array. Una soluzione migliore sarebbe usarlo std::vector<int>e ridimensionarlo a 1000000 elementi.


3
Grazie per la risposta, ma potresti spiegarmi perché gli array sono allocati nello stack e perché no nella memoria principale del programma.
Mayank

18
Il codice dato viene allocato nello stack perché è specificato come un array con un numero costante di elementi in fase di compilazione. I valori vengono messi sul mucchio solo con malloc, new, ecc.
Seth Johnson,

6
Tutte le variabili automatiche vengono allocate nello stack. Se guardi il disasseble vedrai la dimensione delle tue variabili locali sottratte dal puntatore dello stack. Quando chiamate malloc o calloc o una qualsiasi delle funzioni di memoria, le funzioni vanno e trovano blocchi di memoria abbastanza grandi da soddisfare la vostra richiesta.
rieseguire il

@ Carlo perché potremmo allocare più memoria dall'heap, non dallo stack? dalla mia comprensione, sia lo stack che l'heap si muovono in direzione opposta nello spazio degli indirizzi allocato nella memoria.
saurabh agarwal

2
@saurabhagarwal L'heap non si muove. Non è nemmeno una regione di memoria contigua. L'allocatore restituisce semplicemente un blocco di memoria libera che soddisfa i requisiti di dimensione. Cosa e dove sono lo stack e l'heap?
phuclv

56

In C o C ++ gli oggetti locali vengono solitamente allocati nello stack. Stai allocando un array di grandi dimensioni nello stack, più di quanto lo stack possa gestire, quindi stai ottenendo uno stackoverflow.

Non allocarlo localmente in pila, usa invece un altro posto. Ciò può essere ottenuto rendendo globale l'oggetto o allocandolo nell'heap globale . Le variabili globali vanno bene, se non usi le da nessun'altra unità di compilazione. Per assicurarti che ciò non accada per sbaglio, aggiungi uno specificatore di archiviazione statico, altrimenti usa semplicemente l'heap.

Questo allocherà nel segmento BSS, che fa parte dell'heap:

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

Questo verrà allocato nel segmento DATA, che è anche una parte dell'heap:

int c[1000000] = {};
int main()
{
   cout << "done\n";
   return 0;
}

Questo verrà allocato in una posizione non specificata nell'heap:

int main()
{
   int* c = new int[1000000];
   cout << "done\n";
   return 0;
}

Se usi il terzo pattern, allocando sull'heap, non dimenticare di cancellare [] il puntatore ad un certo punto o perderai memoria. Oppure guarda i puntatori intelligenti.
davidA

8
@meowsqueak Ovviamente è una buona pratica deleteovunque ti trovi new. Ma se sei sicuro di allocare la memoria solo una volta (come in main) non è strettamente necessario - la memoria è garantita per essere liberata all'uscita da main anche senza esplicito delete.
Gunther Piez

'at'drhirsch (come si fa a fare un carattere at comunque?) - sì, giusto commento. Poiché l'OP sembra nuovo per la lingua, volevo solo assicurarmi che loro, e chiunque altro vedesse la tua buona risposta, fossero consapevoli delle implicazioni della terza opzione se usata in generale.
davidA

15

Inoltre, se stai utilizzando la maggior parte dei sistemi UNIX e Linux, puoi aumentare temporaneamente la dimensione dello stack con il seguente comando:

ulimit -s unlimited

Ma attenzione, la memoria è una risorsa limitata e da un grande potere derivano grandi responsabilità :)


1
Questa è la soluzione, ma consiglio a tutti di essere estremamente cauti quando si rimuovono questi limiti predefiniti sulla dimensione dello stack del programma. Non solo si verificherà un grave calo delle prestazioni, ma il sistema potrebbe bloccarsi. Ad esempio, ho provato a ordinare un array con 16.000.000 di elementi interi con quicksort su una macchina con 4 GB di RAM e il mio sistema è stato quasi ucciso. LOL
rbaleksandar

@rbaleksandar Penso che il tuo programma da ~ 16 MB abbia quasi ucciso la tua macchina perché stavi lavorando con diverse copie dell'array (potrebbe essere una per chiamata di funzione?) Prova un'implementazione più consapevole della memoria;)
RSFalcon7

Sono abbastanza sicuro che la gestione dell'array sia corretta poiché sto passando per riferimento e non per valore. La stessa cosa accade con bubblesort. Diavolo, anche se la mia implementazione di quicksort fa schifo bubbleort è qualcosa che non puoi implementare in modo errato. LOL
rbaleksandar

LOL potresti provare radix sort, o semplicemente usare std :: sort :)
RSFalcon7

1
Nessuna possibilità. È un compito di laboratorio. : D
rbaleksandar

3

L'array viene allocato nello stack in questo caso, tentare di allocare un array della stessa dimensione utilizzando alloc.


3

Perché memorizzi l'array nello stack. Dovresti conservarlo nel mucchio. Vedere questo collegamento per comprendere il concetto di heap e stack.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.