Pourquoi la taille de la pile est-elle en C# exactement 1 Mo?

de nos jours, les PC ont une grande quantité de mémoire vive, mais la taille de la pile C# n'est que de 1 Mo pour les processus 32 bits et de 4 Mo pour les processus 64 bits ( capacité de la pile dans C# ).

pourquoi la taille de la pile dans CLR est-elle encore si limitée?

et pourquoi exactement 1 MB (4 MB) (et pas 2 MB ou 512 KB)? Pourquoi il a été décidé d'utiliser ces montants?

Je m'intéresse à considérations et motifs derrière cette décision .

40
demandé sur Community 2015-02-22 13:36:38

2 réponses

enter image description here

vous regardez le gars qui a fait ce choix. David Cutler et son équipe ont choisi un mégaoctet comme taille de pile par défaut. Rien à voir avec .NET ou C#, cela a été cloué quand ils ont créé Windows NT. Un mégaoctet est ce qu'il choisit lorsque L'en-tête EXE d'un programme ou L'appel WinAPI CreateThread() ne spécifie pas explicitement la taille de la pile. Ce qui est la manière normale, presque n'importe quel programmeur laisse le système d'exploitation taille.

ce choix est probablement antérieur à la conception de Windows NT, l'histoire est bien trop obscure à ce sujet. Ce serait bien si Cutler écrivait un livre à ce sujet, mais il n'a jamais été écrivain. Il a été extraordinairement influent sur la façon dont les ordinateurs fonctionnent. Son premier système D'exploitation est le RSX-11M, un système d'exploitation 16 bits pour les ordinateurs DEC (Digital Equipment Corporation). Il a fortement influencé le CP/M de Gary Kildall, le premier OS décent pour les microprocesseurs 8 bits. Qui fortement influencé MS-DOS.

sa prochaine conception a été VMS, un système d'exploitation pour les processeurs 32 bits avec support de mémoire virtuelle. Très réussie. Sa prochaine a été annulée par DEC à peu près au moment où la société a commencé à se désintégrer, ne pas être en mesure de rivaliser avec le matériel PC bon marché. Microsoft, ils lui ont fait une offre qu'il ne pouvait pas refuser. Beaucoup de ses collègues se sont joints à lui. Ils ont travaillé sur VMS v2, mieux connu sous le nom de Windows NT. DEC s'est fâché, l'argent a changé de mains. il. Si VMS a déjà choisi un mégaoctet est quelque chose que je ne sais pas, Je ne connais RSX-11 assez bien. Il n'est pas improbable.

assez d'histoire. Un mégaoctet est un lot , un vrai fil consomme rarement plus que quelques poignées de kilo-octets. Donc un mégaoctet est en fait plutôt gaspilleur. C'est cependant le genre de gaspillage que vous pouvez vous permettre sur un système d'exploitation de mémoire virtuelle à la demande, que megabyte est juste mémoire virtuelle . Juste des nombres au processeur, un chacun pour 4096 octets. Vous n'utilisez jamais la mémoire physique, la mémoire vive dans la machine, jusqu'à ce que vous l'adressiez.

c'est excessif dans un programme .NET parce que la taille d'un mégaoctet a été choisie à l'origine pour accommoder les programmes natifs. Qui ont tendance à créer de grands cadres de pile, en stockant des chaînes et des tampons (tableaux) sur la pile aussi bien. Infâme pour être un vecteur d'attaque de malware, un débordement de tampon peut manipuler le programme avec des données. Pas de la façon dont les programmes. net fonctionnent, les chaînes de caractères et les tableaux sont attribués sur le tas GC et l'indexation est vérifiée. La seule façon d'attribuer l'espace sur la pile avec C# est avec le mot-clé stackalloc .

le seul usage non-trivial de la pile dans .NET est par le jitter. Il utilise la pile de votre thread pour compiler MSIL à la machine juste à temps. Je n'ai jamais vu ou vérifier combien d'espace il exige, plutôt dépend de la nature du code et si l'optimiseur est activé ou non, mais quelques dizaines de kilo-octets est une approximation. Ce qui explique que ce site ait reçu son nom, un débordement de pile dans un programme .NET est fatal. Il ne reste pas assez d'espace (moins de 3 kilooctets) pour lancer de façon fiable tout code qui tenterait d'attraper l'exception. Kaboom de bureau est la seule option.

enfin et surtout, un programme .NET fait quelque chose d'improductif avec le pile. Le CLR commit la pile d'un fil. C'est un mot cher qui signifie qu'il ne se contente pas de réserver la taille de la pile, il s'assure également que l'espace est réservé dans le fichier de pagination du système d'exploitation de sorte que la pile peut toujours être échangé lorsque nécessaire. Le défaut de commettre est une erreur fatale et met fin à un programme sans condition. Cela ne se produit que sur une machine avec très peu de mémoire vive qui exécute un trop grand nombre de processus, une telle machine aura tourné vers la mélasse avant que les programmes commencent à mourir. Un problème possible il y a plus de 15 ans, pas aujourd'hui. Les programmeurs qui ajustent leur programme pour agir comme une voiture de course de F1 utilisent l'élément <disableCommitThreadStack> dans leur .fichier de configuration.

FWIW, Cutler n'a pas arrêté de concevoir des systèmes d'exploitation. Cette photo a été faite pendant qu'il travaillait sur Azure.


" J'ai remarqué que .NET n'engage plus la pile. Pas exactement quand ou pourquoi c'est arrivé, ça fait trop longtemps que je n'ai pas vérifié. Je suppose que ce changement de design s'est produit quelque part autour de .NET 4.5. Un changement assez sensé.

93
répondu Hans Passant 2017-06-08 13:54:32

la taille de la pile réservée par défaut est spécifiée par le linker et elle peut être dépassée par les développeurs via la modification de la valeur PE au moment du lien ou pour un thread individuel en spécifiant le paramètre dwStackSize pour la fonction CreateThread WinAPI.

si vous créez un thread dont la taille initiale de la pile est supérieure ou égale à la taille par défaut de la pile, il est arrondi au multiple de 1 MB le plus proche.

pourquoi la valeur égale à 1 MB pour les processus 32 bits et 4 Mo pour les 64 bits? Je pense que vous devriez demander aux développeurs, qui a conçu Windows, ou attendre que quelqu'un d'eux répond à votre question.

probablement Mark Russinovich sait cela et vous pouvez le contacter lui. Peut-être que vous pouvez trouver cette information dans ses livres internes Windows plus tôt que la sixième édition qui décrit moins d'informations sur les piles plutôt que son article . Ou peut-être que Raymond Chen connaît les raisons depuis qu'il écrit des choses intéressantes sur les fenêtres internes et son histoire. Il peut répondre à votre question aussi, mais vous devriez poster une suggestion à la Boîte À suggestions .

mais en ce moment je vais essayer d'expliquer quelques raisons probables Pourquoi Microsoft ont choisi ces valeurs en utilisant MSDN, Mark's et les blogs de Raymond.

les valeurs par défaut ont ces valeurs probablement parce que dans les premiers temps les PCs étaient lents et allouer la mémoire sur la pile était beaucoup plus rapide que l'allocation de mémoire dans le tas. Et comme les attributions par Cheminée étaient beaucoup moins chères, elles ont été utilisées, mais elles nécessitaient une plus grande taille.

donc la valeur était la taille optimale de la pile réservée pour la plupart des applications. Il est optimal parce qu'il permet de faire beaucoup d'appels imbriqués et d'allouer de la mémoire sur la pile pour passer des structures aux fonctions d'appel. En même temps il permet de créer beaucoup de threads.

de nos jours, ces valeurs sont principalement utilisées pour la rétrocompatibilité, parce que les structures qui sont passées comme paramètres aux fonctions WinAPI sont encore attribuées sur la pile. Mais si vous n'utilisez pas les attributions de pile, l'utilisation de la pile d'un thread sera nettement inférieure à la valeur par défaut de 1 MB, ce qui est un gaspillage, comme L'a mentionné Hans Passant. Et pour éviter cela, L'OS n'engage que la première page de la pile (4 Ko), Si autre n'est pas spécifié dans l'en-tête PE de l'application. Les autres pages sont attribuées sur demande.

Certaines applications outrepassent l'espace réservé à l'adresse et s'engagent initialement à optimiser l'utilisation de la mémoire. Par exemple, la taille maximale d'une pile de thread d'un processus natif IIS est de 256 KB ( KB932909 ). Et cette diminution des valeurs par défaut est recommandé par Microsoft:

il est préférable de choisir une taille de pile aussi petite que possible et engager la pile qui est nécessaire pour le fil ou la fibre pour fonctionner de manière fiable. Chaque page est réservée pour la pile ne peut pas être utilisé pour d'autres fins.

Sources:

  1. la Taille de la Pile (MSDN)
  2. repousser les limites des fenêtres: processus et fils (Mark Russinovich)
  3. par défaut, la taille maximale de la pile d'un thread qui est créé dans un processus natif IIS est de 256 KB (KB932909)
1
répondu Yoh Deadfall 2015-12-24 14:37:46