C / C ++ taille maximale de la pile du programme

115

Je veux faire DFS sur un tableau 100 X 100. (Disons que les éléments du tableau représentent les nœuds du graphe) Donc, en supposant le pire des cas, la profondeur des appels de fonction récursifs peut aller jusqu'à 10000, chaque appel prenant jusqu'à 20 octets. Est-ce donc faisable signifie qu'il y a une possibilité de stackoverflow?

Quelle est la taille maximale de la pile en C / C ++?

Veuillez spécifier pour gcc pour les deux
1) cygwin sous Windows
2) Unix

Quelles sont les limites générales?

avd
la source
11
Vous savez que vous pouvez implémenter une recherche en profondeur sans récursivité, non?
Sebastian
4
Non, je ne sais pas, veuillez expliquer.
avd
1
J'ai fait un petit exemple de DFS sans récursivité dans ma réponse
Andreas Brinck
56
plus un pour une question sur le débordement de pile réel
Sam Watkins
3
@SamWatkins ouais, l'un des plus gros problèmes pour moi avec le nom Stack Overflow est que je pourrais rechercher un "débordement de pile" sur Google et me retrouver sur ce site Web, mais pas nécessairement / moins probable dans des questions sur les débordements de pile ...
lalilulelost

Réponses:

106

Dans Visual Studio, la taille de pile par défaut est de 1 Mo, je pense, donc avec une profondeur de récursivité de 10000, chaque frame de pile peut être au plus ~ 100 octets, ce qui devrait être suffisant pour un algorithme DFS.

La plupart des compilateurs, y compris Visual Studio, vous permettent de spécifier la taille de la pile. Sur certaines (toutes?) Saveurs Linux, la taille de la pile ne fait pas partie de l'exécutable mais d'une variable d'environnement dans le système d'exploitation. Vous pouvez ensuite vérifier la taille de la pile avec ulimit -set la définir sur une nouvelle valeur avec par exemple ulimit -s 16384.

Voici un lien avec les tailles de pile par défaut pour gcc.

DFS sans récursivité:

std::stack<Node> dfs;
dfs.push(start);
do {
    Node top = dfs.top();
    if (top is what we are looking for) {
       break;
    }
    dfs.pop();
    for (outgoing nodes from top) {
        dfs.push(outgoing node);
    }
} while (!dfs.empty())
Andreas Brinck
la source
12
Et juste pour référence, un BFS est le même sauf que vous utilisez un FIFO au lieu d'une pile.
Steve Jessop
Oui, ou en langage STL, utilisez un std :: deque avec pop_front / push_back
Andreas Brinck
votre DFS avec les résultats de la pile sera différent de la version de récursivité. Dans certains cas, cela n'a pas d'importance, mais dans d'autres (par exemple en tri topologique), vous obtiendrez de mauvais résultats
spin_eight
Oui, la limite par défaut pour VS est en effet de 1 Mo. Plus d'informations et la façon de définir une valeur différente peuvent être trouvées dans la documentation Microsoft: msdn.microsoft.com/en-us/library/tdkhxaks(v=vs.140).aspx
FrankS101
Je préfère utiliser une structure de données de pile explicite pour de tels algorithmes, plutôt que la récursivité, afin que 1. ne dépende pas de la taille de la pile système, 2. puisse changer l'algorithme pour utiliser une structure de données différente, par exemple une file d'attente ou une file d'attente prioritaire sans lancer tout le code.
Sam Watkins
47

les piles de fils sont souvent plus petites. Vous pouvez modifier la valeur par défaut au moment de la liaison ou la modifier également au moment de l'exécution. Pour référence, certains paramètres par défaut sont:

  • glibc i386, x86_64 7,4 Mo
  • Tru64 5,1 5,2 Mo
  • Cygwin 1,8 Mo
  • Solaris 7..10 1 Mo
  • MacOS X 10.5 460 Ko
  • AIX 5 98 Ko
  • OpenBSD 4.0 64 Ko
  • HP-UX 11 16 Ko
pixelbeat
la source
14
Déterminé empiriquement par Bruno Haible lists.gnu.org/archive/html/bug-coreutils/2009-10/msg00262.html
pixelbeat
17

Dépendant de la plate-forme, de la chaîne d'outils, de l'ultime limite, des paramètres ... Ce n'est pas du tout spécifié et de nombreuses propriétés statiques et dynamiques peuvent l'influencer.

DrPizza
la source
4
Il n'y a pas de «limites générales». Sous Windows, avec les options de l'éditeur de liens VC ++ par défaut et le comportement CreateThread par défaut, généralement quelque chose d'environ 1 Mio par thread. Sur Linux, avec un utilisateur illimité, je pense qu'il n'y a généralement pas de limite (la pile peut simplement croître vers le bas pour occuper presque tout l'espace d'adressage). En gros, si vous devez demander, vous ne devriez pas utiliser la pile.
DrPizza
1
Sur les systèmes embarqués, vous pouvez avoir 4k ou moins. Dans ce cas, vous devez demander même s'il est raisonnable d'utiliser la pile. La réponse est généralement un haussement d'épaules gaulois.
Steve Jessop
1
Ah vrai, aussi souvent le cas en mode noyau.
DrPizza
6

Oui, il existe une possibilité de débordement de pile. Les standards C et C ++ ne dictent pas des choses comme la profondeur de la pile, ce sont généralement un problème environnemental.

La plupart des environnements de développement et / ou des systèmes d'exploitation décents vous permettront d'adapter la taille de la pile d'un processus, que ce soit au moment de la liaison ou du chargement.

Vous devez spécifier le système d'exploitation et l'environnement de développement que vous utilisez pour une assistance plus ciblée.

Par exemple, sous Ubuntu Karmic Koala, la valeur par défaut pour gcc est 2M réservés et 4K validés, mais cela peut être modifié lorsque vous liez le programme. Utilisez l' --stackoption de ldpour le faire.

paxdiablo
la source
2
@lex: il n'y a pas de limites générales. Cela dépend de nombreux paramètres.
Michael Foukarakis
@paxdiablo: Quelle est la signification de réservé et engagé?
avd
2
Réservé correspond à la quantité d'espace d'adressage à allouer, engagé à la quantité à laquelle attacher le stockage de sauvegarde. En d'autres termes, réserver l'espace d'adressage ne signifie pas que la mémoire sera là quand vous en aurez besoin. Si vous n'utilisez jamais plus de 4K stack, vous ne gaspillez pas de vraie mémoire pour l'autre 1.6M. Si vous voulez garantir qu'il y aura suffisamment de pile, réservée et validée doivent être identiques.
paxdiablo
2
@paxdiablo 2M - 4k n'est pas 1,6M. Juste dire. (m'a confus les 3 premières fois que j'ai lu votre commentaire)
griffin
2
@griffin, bravo pour la première personne à avoir attrapé ça dans 3+ ans. Je voulais bien sûr dire "reste de celui-ci"
j'éviterai
5

Je viens de manquer de pile au travail, c'était une base de données et elle exécutait des threads, fondamentalement, le développeur précédent avait jeté un gros tableau sur la pile, et la pile était de toute façon faible. Le logiciel a été compilé à l'aide de Microsoft Visual Studio 2015.

Même si le thread était à court de pile, il échouait silencieusement et continuait, il ne débordait que lorsqu'il s'agissait d'accéder au contenu des données de la pile.

Le meilleur conseil que je puisse donner est de ne pas déclarer de tableaux sur la pile - en particulier dans les applications complexes et en particulier dans les threads, utilisez plutôt heap. C'est pour ça qu'il est là;)

Gardez également à l'esprit qu'il peut ne pas échouer immédiatement lors de la déclaration de la pile, mais uniquement lors de l'accès. Je suppose que le compilateur déclare la pile sous Windows "de manière optimiste", c'est-à-dire qu'il supposera que la pile a été déclarée et est suffisamment dimensionnée jusqu'à ce qu'il vienne à l'utiliser et découvre ensuite que la pile n'est pas là.

Différents systèmes d'exploitation peuvent avoir des stratégies de déclaration de pile différentes. Veuillez laisser un commentaire si vous connaissez ces politiques.

Hibou
la source
3

Je ne suis pas sûr de ce que vous entendez en effectuant une première recherche en profondeur sur un tableau rectangulaire, mais je suppose que vous savez ce que vous faites.

Si la limite de pile est un problème, vous devriez être en mesure de convertir votre solution récursive en une solution itérative qui pousse les valeurs intermédiaires sur une pile qui est allouée à partir du tas.

Dave Kirby
la source