web-dev-qa-db-fra.com

Combien d'utilisation de la pile est trop?

Dernièrement, lorsque j'ai écrit du C ou du C++, je déclarerai toutes mes variables sur la pile simplement parce que c'est une option, contrairement à Java.

Cependant, j'ai entendu dire que c'est une mauvaise idée de déclarer de grandes choses sur la pile.

  1. Pourquoi est-ce exactement le cas? Je pense que le débordement de pile est impliqué, mais je ne sais pas très bien pourquoi cela se produit.
  2. Combien de choses sur la pile, c'est trop?

Je n'essaye pas de mettre des fichiers de 100 Mo sur la pile, juste une douzaine de tableaux de kilo-octets à utiliser comme tampons de chaîne ou autre. Est-ce trop d'utilisation de la pile?

(Désolé en cas de doublon, la recherche de la pile continue de donner des références à Stack Overflow. Il n'y a même pas de balise de pile d'appel, je viens d'utiliser l'abstrait.)

26
Elliot Way

Cela dépend de votre système d'exploitation. Sous Windows, la taille maximale typique d'une pile est de 1 Mo, alors qu'elle est de 8 Mo sur un Linux moderne typique, bien que ces valeurs soient ajustables de diverses manières. Si la somme de vos variables de pile (y compris les frais généraux de bas niveau tels que les adresses de retour, les arguments basés sur la pile, les espaces réservés de valeur de retour et les octets d'alignement) dans la pile d'appel entière dépasse cette limite, vous obtenez un débordement de pile, qui supprime généralement votre programme sans aucune chance de récupération.

Quelques kilo-octets suffisent généralement. Des dizaines de kilo-octets sont dangereux car ils commencent à résumer. Des centaines de kilo-octets sont une très mauvaise idée.

22
Sebastian Redl

La seule réponse valable est vague: "trop, c'est quand la pile déborde."

À moins que vous ne maîtrisiez complètement l'implémentation de chaque ligne de code entre le point d'entrée du programme et la fonction en question, vous ne pouvez faire aucune hypothèse sur la quantité de pile disponible. Vous ne pouvez pas, par exemple, garantir que l'appel de cette fonction ne provoquera jamais un débordement de pile:

void break_the_camels_back()
{
    int straw;
    ...
}

La pile par défaut de 8 Mio sur les Unix modernes est beaucoup d'espace pour les piles, en particulier pour quelqu'un comme moi qui est assez bon pour se souvenir des processeurs avec des pointeurs de pile 8 bits. La réalité pratique est qu'il est peu probable que vous passiez à travers sans essayer. Si vous le faites, le dépassement de la limite de pile est généralement considéré comme une violation de segmentation, et les systèmes avec suffisamment de gestion de la mémoire pour le détecter enverront un SIGSEGV quand cela se produira.

Vous avez quelques options. La première consiste à ne pas deviner la quantité de pile disponible et à demander au système. Tout ce qui est conforme à POSIX aura une fonction getrlimit(2) qui vous indiquera la limite supérieure. RLIMIT_STACK Est la limite spécifique que vous souhaitez. La seconde consiste à surveiller la quantité de pile utilisée par vos programmes et à prendre des décisions concernant les variables automatiques par rapport à l'allocation dynamique de mémoire en fonction de cela. Il n'y a, à ma connaissance, aucune fonction standard pour déterminer la quantité de pile utilisée, mais des programmes comme valgrind peuvent l'analyser pour vous.

11
Blrfl

Si vous allouez un tableau de 10 000 octets par exemple à la pile, ce tableau est de taille limitée. 10 000 peut être beaucoup, mais si vous avez besoin de 10 001 octets, votre programme peut se bloquer ou pire. Donc, dans cette situation, vous voulez quelque chose qui s'adapte à la taille dont vous avez besoin et que quelque chose ne soit pas sur la pile.

Les tableaux de taille fixe pour les tampons de chaîne sur la pile ne sont pas un problème car ils gardent la mémoire sur la pile, ils sont un problème parce que les tampons de taille fixe sont un problème fatal qui attend de se produire.

Mais si vous utilisez C++ et déclarez par exemple une chaîne std :: ou std :: vec sur la pile, alors ce qui se trouve sur la pile sera en fait d'une taille fixe et petite. Les données réelles seront stockées sur le tas. Vous pouvez stocker un million de caractères dans une instance std :: string, et cela ne prendra qu'une très petite quantité de données (généralement 8 à 24 octets, selon l'implémentation) sur la pile, et un million d'octets sur le tas.

4
gnasher729

Eh bien 1 Mo est une bonne estimation pour * nix. La récursivité peut être une raison majeure de dépassement de pile en combinaison avec des allocations de pile. Cependant, dans la plupart des cas, les objets divins qui sembleraient superficiellement trop gros pour être placés sur la pile sont bien conçus pour gérer leur mémoire interne sur le tas et utiliser la pile uniquement comme un moyen d'être automatiquement détruit lorsque la pile est sautée. Le destructeur libérera les énormes morceaux de mémoire gérés en interne. Les conteneurs std sont conçus de cette façon, et les pointeurs partagés/uniques sont également conçus de cette façon.

L'important est de ne pas allouer de gros morceaux de mem brut sur la pile comme char [1024 * 1024] et de concevoir des classes pour encapsuler les allocations de tas et utiliser la pile uniquement pour la commodité d'appeler automatiquement le destructeur.

3
Asterisk