2009-10-13 12 views
13

Dans votre expérience de programmation actuelle, comment cette connaissance de STACK et HEAP vous a-t-elle réellement sauvé dans la vie réelle? Une histoire des tranchées? Ou ce concept est-il bon pour remplir des livres de programmation et bon pour la théorie?Stack vs. Heap in .NET

+2

Ceci est plus d'un sujet de discussion d'une question avec une vraie réponse; envisager de passer à un wiki. –

+0

Il semble plus d'une discussion étant donné les réponses postées jusqu'à présent. On peut répondre à cette question soit «Concept non utile», soit «Concept utile et * voici un exemple de comment *». "Concept utile" sans exemple spécifique ne répond pas réellement à la question. – sylvanaar

+0

voir ce post parle de la pile et tas pour.net http://stackoverflow.com/questions/12727821/net-stack-and-heap-what-goes-where-when-i-declare-a-string/12728239#12728239 – DRobertE

Répondre

12

Pour moi, c'est la différence entre être un «développeur/programmeur» et un «artisan».N'importe qui peut apprendre à écrire du code et à voir comment les choses arrivent "magiquement" pour que vous ne sachiez pas pourquoi/comment. Pour être vraiment utile dans ce que vous faites, je pense qu'il est très important de connaître autant que possible le cadre que vous utilisez. Rappelez-vous qu'il est non seulement une langue , il est un cadre qui vous tirez parti pour créer la meilleure application à vos capacités.

J'ai analysé beaucoup de mémoire sur les années et l'a trouvé très utile de savoir les internes et les différences entre les deux. La plupart d'entre elles ont été des conditions OutOfMemory et des applications instables. Cette connaissance est absolument nécessaire pour utiliser WinDbg lorsque vous regardez des dumps. Lorsque vous étudiez un vidage de mémoire, sachez comment la mémoire est allouée entre le processus noyau/utilisateur et le CLR, vous pouvez au moins vous indiquer où commencer votre analyse. Par exemple, prenons un cas MOO: La mémoire allouée que vous voyez dans les tailles de tas, jeu de travail, mémoire privée, mémoire partagée, mémoire virtuelle, mémoire validée, poignées et threads peut être un grand indicateur de l'endroit où commencer.

Il environ 8 tas différents que le CLR utilise:

  1. Loader Heap: contient des structures CLR et le système de type
  2. haute fréquence Heap: Statique, MethodTables, FieldDescs, carte d'interface
  3. basse fréquence Heap: EEClass, ClassLoader et tables de recherche
  4. Heap Stub: stubs pour CAS, wrappers COM, P/Invoke
  5. Heap d'objets volumineux: allocations de mémoire nécessitant plus de 85 k octets
  6. GC Heap: l'utilisateur alloué tas mémoire privée à l'application
  7. code JIT Heap: mémoire allouée par mscoreee (moteur d'exécution) et le compilateur JIT pour le code managé
  8. Processus/Base de Heap: PIA/allocations non gérés, natif mémoire, etc

trouver ce tas a des allocations élevées peuvent me dire si je fragmentation de la mémoire, les fuites de mémoire gérées, PIA/fuites non gérés, etc.

Sachant que vous avez 1MB (x86)/4Mo (sur x64) de l'espace de pile alloué pour chaque thread L'utilisation de votre application me rappelle que si j'ai 100 threads, vous aurez 100 Mo supplémentaires d'utilisation de la mémoire virtuelle.

J'ai eu un client qui avait des serveurs Citrix écraser avec des problèmes OutOfMemory, étant lente réactivité instable, lorsque leur application a été en cours d'exécution sur elle en plusieurs sessions. Après avoir regardé la décharge (je n'avais pas accès au serveur), j'ai vu qu'il y avait plus de 700 threads utilisés par cette instance de l'application! Connaissant l'allocation de la pile de threads, m'a permis de corréler les MOO ont été causés par l'utilisation de thread élevé.

En bref, à cause de ce que je fais pour mon « rôle », il est de notoriété inestimable d'avoir. Bien sûr, même si vous ne déboguez pas les vidages mémoire, ça ne fait jamais mal non plus!

+0

Je voudrais juste ajouter pour complétude: Alors que chaque thread a une pile par défaut de 1 MiB, cela ne signifie pas que la mémoire est validée (ce n'est pas le cas, du moins pas sur Windows 7 64 bits avec .NET cadre 4). Les valeurs par défaut que j'ai vues sont plus proches de 4 kiB par défaut. Il faut donc 1 Mo d'espace d'adressage virtuel, mais pas 1 Mo de mémoire physique (que ce soit un fichier de page, un autre fichier mappé en mémoire ou une RAM réelle). Sur un système 64 bits, vous pouvez avoir des milliers de piles et ne prendre que quelques méga-mémoire. En fait, j'ai vu le tas géré allouer des TiB, tout en ne validant que quelques Mo. – Luaan

+0

Merci de noter la nécessité de clarifier - J'ai modifié ma réponse pour appeler explicitement la mémoire virtuelle au lieu de commettre. –

3

Personnellement, c'est l'une des très rares questions techniques que je pose à chaque personne que je vais engager. Je pense qu'il est essentiel de comprendre comment utiliser le framework .NET (et la plupart des autres langages). Je n'embauche jamais quelqu'un qui n'a pas une compréhension claire de l'utilisation de la mémoire sur la pile par rapport au tas. Sans comprendre cela, il est presque impossible de comprendre le garbage collector, comprendre les caractéristiques de performance .NET, et de nombreux autres problèmes de développement critiques.

+3

Je suis d'accord avec vous, mais vous n'avez vraiment pas donné un bon exemple de ce qu'il faut savoir sur la pile et le tas. Je suis d'accord pour apprendre quelque chose de nouveau :) –

+5

Je suis d'accord avec leppie, la distinction entre une référence et un type de valeur est très importante, mais qu'ils finissent sur la pile ou le tas ... vous ne m'avez pas convaincu pourquoi cela aurait de l'importance tellement de. –

+0

Eh bien, je demande généralement en termes généraux, et essayer d'obtenir le candidat pour expliquer la différence pour moi. Cela est devenu l'un de mes points de repère sur le niveau de compréhension - je pense que quelqu'un qui sait comment fonctionne l'allocation de mémoire dans .NET sera au moins désireux et capable d'apprendre à peu près tout ce qui est nécessaire. Je pense que vous devez comprendre 1) La pile, en termes généraux, 2) Le tas, en termes généraux, 3) Comment les types de référence fonctionnent, 4) Comment les types de valeur fonctionnent, 5) Argument passant en utilisant ref/out, et comment diffère de par la valeur, en particulier avec les types de référence (pas pile/tas, mais semi-connexes) –

16

La distinction en .NET entre la sémantique des types de référence et des types de valeur est un concept beaucoup plus important à saisir.

Personnellement, je n'ai jamais pris la peine de penser à la pile ou au tas dans toutes mes années de codage (juste basé sur CLR).

+1

mmm - Il est difficile de comprendre la sémantique du type de référence et du type de valeur (en particulier le pourquoi derrière) sans comprendre la pile et le tas. –

+0

Peut-être une meilleure question serait: "Expliquer pourquoi value :: reference! = Stack :: heap". :) –

+0

Jon Skeet a déjà répondu à cette question http://www.yoda.arachsys.com/csharp/memory.html – MarkJ

4

Je ne pense pas que ce soit important si vous ne faites que construire des applications métier moyennes, ce qui est le cas de la plupart des programmeurs .NET.

Les livres que j'ai vus mentionnent simplement pile et tas en passant comme si mémoriser ce fait est d'une importance monumentale.

0

La distinction importante entre les types de référence et types de valeur. Ce n'est pas vrai que "les types de valeur vont sur la pile, les types de référence vont sur le tas". Jon Skeet a écrit about this et a donc Eric Lippert.

0

Nous avions une entité de réclamation (objet de gestion) qui contenait des données pour une réclamation entière. L'une des exigences de l'application consistait à créer une piste d'audit de chaque valeur unique modifiée par l'utilisateur. Pour ce faire, nous ne conserverions pas deux fois la base de données, mais conserverions l'entité de revendication initiale dans le formulaire et une entité de réclamation de travail. L'entité de réclamation de travail serait mise à jour lorsque l'utilisateur cliquait sur Sauvegarder et nous comparerions alors les propriétés de l'entité de revendication d'origine avec les propriétés d'entité de réclamation de travail correspondantes pour déterminer ce qui avait changé. Un jour, nous avons remarqué que notre méthode de comparaison ne trouve jamais de différence. C'est là que ma compréhension de la pile et du tas a sauvé mon extrémité arrière (en particulier les types de valeur et les types de référence). Parce que nous avions besoin de maintenir des copies du même objet en mémoire le développeur simplement créé deux objets

Dim originalClaim As ClaimBE 
Dim workingClaim As ClaimBE 

alors appelé la méthode de la couche d'affaires pour renvoyer l'objet de réclamation et attribuer la même claimBE aux deux variables

originalClaim = BLL.GetClaim() 
workingClaim = originalClaim 

donc deux types de référence pointant vers le même type de valeur. Cauchemar évité.

+1

Votre histoire n'a rien à voir faire la pile contre le tas; c'est seulement la valeur par rapport à la référence. Comme d'autres l'ont dit, les types de valeur ont la particularité de pouvoir être stockés sur la pile, mais c'est là que la relation se termine. Le fait que 'originalClaim' et' workingClaim' aient été stockés sur la pile ou le tas n'a aucune importance pour votre histoire. – Gabe

+0

@Gabe Encore plus drôle, les types de référence peuvent également aller sur pile. Cela n'arrive pas souvent (un exemple est le mot clé 'stackalloc' dans un contexte non sécurisé), mais cela pourrait changer dans les futures versions de .NET si cela en vaut la peine, ce qui serait d'une grande aide lors de l'allocation de lourdes opérations. utiliser les objets alloués à l'intérieur d'une portée donnée - pas besoin de mettre cela sur le tas pour que le GC puisse collecter plus tard, il suffit d'utiliser pile, pousser, pop, done, pas besoin de GC. – Luaan