134 votes

Défaut de segmentation sur les tableaux de grande taille

Le code suivant me donne une erreur de segmentation lorsqu'il est exécuté sur une machine de 2 Go, mais fonctionne sur une machine de 4 Go.

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

La taille du tableau n'est que de 4Mb. Y a-t-il une limite à la taille d'un tableau qui peut être utilisé en c++ ?

151voto

Charles Salvia Points 28661

Vous avez probablement un débordement de pile ici. Le tableau est trop grand pour tenir dans l'espace d'adresse de la pile de votre programme.

Si vous allouez le tableau sur le tas, tout devrait bien se passer, en supposant que votre machine dispose de suffisamment de mémoire.

int* array = new int[1000000];

Mais n'oubliez pas que cela vous obligera à delete[] le tableau. Une meilleure solution serait d'utiliser std::vector<int> et le redimensionner à 1000000 éléments.

4 votes

Merci pour la réponse, mais pourriez-vous m'expliquer pourquoi les tableaux sont alloués sur la pile et pourquoi pas dans la mémoire principale du programme.

23 votes

Le code donné alloue sur la pile car il est spécifié comme un tableau avec un nombre constant d'éléments au moment de la compilation. Les valeurs ne sont placées sur le tas qu'avec malloc, new, etc.

7 votes

Toutes les variables automatiques sont allouées sur la pile. Si vous regardez la disasseble, vous verrez la taille de vos variables locales soustraite du pointeur de pile. Lorsque vous appelez malloc ou calloc ou n'importe quelle fonction mémoire, les fonctions vont chercher des blocs de mémoire suffisamment grands pour répondre à votre demande.

63voto

hirschhornsalz Points 16306

En C ou C++, les objets locaux sont généralement alloués sur la pile. Vous allouez un grand tableau sur la pile, plus que ce que la pile peut gérer, et vous obtenez donc un message d'erreur stackoverflow.

Ne l'allouez pas localement sur la pile, utilisez un autre endroit à la place. Ceci peut être réalisé soit en rendant l'objet mondial ou l'allouer sur la base globale amas . Les variables globales sont acceptables si vous ne les utilisez pas à partir d'une autre unité de compilation. Pour être sûr que cela ne se produise pas par accident, ajoutez un spécificateur de stockage statique, sinon utilisez simplement le tas.

Cette allocation se fera dans le segment BSS, qui est une partie du tas :

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

Cette allocation se fera dans le segment DATA, qui fait également partie du tas :

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

Cela va allouer à un emplacement non spécifié dans le tas :

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

1 votes

Si vous utilisez le troisième modèle, en allouant sur le tas, n'oubliez pas de supprimer[] le pointeur à un moment donné, sinon vous aurez une fuite de mémoire. Ou regardez du côté des pointeurs intelligents.

10 votes

@meowsqueak Bien sûr, c'est une bonne pratique de delete partout où l'on alloue avec new . Mais si vous êtes sûrs de n'allouer de la mémoire qu'une seule fois (comme dans main), ce n'est absolument pas nécessaire - la mémoire est garantie d'être libérée à la sortie de main même sans explicite delete .

0 votes

At'drhirsch (comment fait-on un at-character de toute façon ?) - oui, c'est juste. Comme l'OP semble être novice dans la langue, je voulais juste m'assurer qu'il était conscient des implications de la troisième option si elle est utilisée de manière générale, ainsi que tous ceux qui ont vu votre bonne réponse.

22voto

RSFalcon7 Points 542

En outre, si vous utilisez la plupart des systèmes UNIX et Linux, vous pouvez augmenter temporairement la taille de la pile en utilisant la commande suivante :

ulimit -s unlimited

Mais attention, la mémoire est une ressource limitée et avec un grand pouvoir viennent de grandes responsabilités :)

2 votes

C'est la solution, mais je vous conseille d'être extrêmement prudent lorsque vous supprimez les limites par défaut de la taille de la pile du programme. Non seulement vous subirez une baisse importante des performances, mais votre système risque de planter. Par exemple, j'ai essayé de trier un tableau de 16 000 000 d'éléments entiers avec quicksort sur une machine avec 4GB RAM et mon système a été presque tué. LOL

1 votes

@rbaleksandar Je pense que votre programme de ~16MB a presque tué votre machine parce que vous travailliez avec plusieurs copies du tableau (peut-être une par appel de fonction ?) essayez une implémentation plus consciente de la mémoire ;)

0 votes

Je suis presque sûr que la gestion des tableaux est correcte puisque je passe par référence et non par valeur. La même chose se produit avec bubblesort. Bon sang, même si mon implémentation de quicksort est nulle, bubblesort est quelque chose que vous ne pouvez pas implémenter incorrectement. LOL

3voto

rerun Points 15285

Votre tableau est en train d'être alloué sur la pile, dans ce cas, essayez d'allouer un tableau de la même taille en utilisant alloc.

3voto

Narek Points 7815

Parce que vous stockez le tableau dans la pile. Vous devriez le stocker dans le tas. Voir ce lien pour comprendre le concept de tas et de pile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X