Question

Une question récente littéraux chaîne dans .NET a attiré mon attention. Je sais que les chaînes littérales sont internées pour différentes chaînes avec la même valeur se réfèrent au même objet . Je sais aussi qu'une chaîne peut être interné à l'exécution:

string now = DateTime.Now.ToString().Intern(); 

Il est évident qu'une chaîne qui est interné à l'exécution se trouve sur le tas, mais je l'avais supposé qu'un littéral est placé dans le segment des données du programme (et dit dans mon réponse à ladite question). Cependant, je ne me souviens pas avoir vu ça nulle part. Je suppose que cela est le cas puisque c'est comment je le ferais et le fait que l'instruction IL est utilisé ldstr pour obtenir littéraux et aucune allocation semble avoir lieu me semble sauvegarder.

Pour couper une longue histoire courte, où vont-littéraux de chaîne résident? Est-ce sur le tas, le segment de données ou d'une place, je ne l'ai pas pensé?


Modifier Si les chaînes littérales ne résider sur le tas, quand sont-ils attribués?

Était-ce utile?

La solution

Strings dans .NET sont des types de référence, ils sont toujours sur le tas (même quand ils sont internés). Vous pouvez le vérifier à l'aide d'un débogueur tel que WinDbg.

Si vous avez la classe ci-dessous

   class SomeType {
      public void Foo() {
         string s = "hello world";
         Console.WriteLine(s);
         Console.WriteLine("press enter");
         Console.ReadLine();
      }
   }

Et vous appelez sur une instance Foo(), vous pouvez utiliser WinDbg pour inspecter le tas.

La référence sera très probablement stocké dans un registre pour un petit programme, donc le plus facile est de trouver la référence à la chaîne spécifique en faisant une !dso. Cela nous donne l'adresse de notre chaîne en question:

0:000> !dso
OS Thread Id: 0x1660 (0)
ESP/REG  Object   Name
002bf0a4 025d4bf8 Microsoft.Win32.SafeHandles.SafeFileHandle
002bf0b4 025d4bf8 Microsoft.Win32.SafeHandles.SafeFileHandle
002bf0e8 025d4e5c System.Byte[]
002bf0ec 025d4c0c System.IO.__ConsoleStream
002bf110 025d4c3c System.IO.StreamReader
002bf114 025d4c3c System.IO.StreamReader
002bf12c 025d5180 System.IO.TextReader+SyncTextReader
002bf130 025d4c3c System.IO.StreamReader
002bf140 025d5180 System.IO.TextReader+SyncTextReader
002bf14c 025d5180 System.IO.TextReader+SyncTextReader
002bf15c 025d2d04 System.String    hello world             // THIS IS THE ONE
002bf224 025d2ccc System.Object[]    (System.String[])
002bf3d0 025d2ccc System.Object[]    (System.String[])
002bf3f8 025d2ccc System.Object[]    (System.String[])

Utilisez maintenant pour savoir !gcgen quelle génération l'instance est:

0:000> !gcgen 025d2d04 
Gen 0

Il est dans la génération zéro - à-dire qu'elle a alloué être juste. Qui est l'enracinant?

0:000> !gcroot 025d2d04 
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 0 OSTHread 1660
ESP:2bf15c:Root:025d2d04(System.String)
Scan Thread 2 OSTHread 16b4
DOMAIN(000E4840):HANDLE(Pinned):6513f4:Root:035d2020(System.Object[])->
025d2d04(System.String)

L'ESP est la pile pour notre méthode object[], mais notez que nous avons aussi bien <=>. C'est la table de stagiaire. Jetons un coup d'oeil.

0:000> !dumparray 035d2020
Name: System.Object[]
MethodTable: 006984c4
EEClass: 00698444
Size: 528(0x210) bytes
Array: Rank 1, Number of elements 128, Type CLASS
Element Methodtable: 00696d3c
[0] 025d1360
[1] 025d137c
[2] 025d139c
[3] 025d13b0
[4] 025d13d0
[5] 025d1400
[6] 025d1424
...
[36] 025d2d04  // THIS IS OUR STRING
...
[126] null
[127] null

réduit la sortie un peu, mais vous voyez l'idée.

En conclusion : les chaînes sont sur le tas - même quand ils sont internés. Le tableau interné contient une référence à l'instance sur le tas. C'est à dire. chaînes internées ne sont pas collectées au cours de GC, car les racines de table internées eux.

Autres conseils

moi si je me trompe, mais ne sont pas tous les objets se trouvent sur le tas, dans Java et .NET?

Dans .Net, littéraux de chaîne quand « interné », sont stockés dans une structure de données spéciale appelée, la « table interne ». Il est distinct du tas et la pile. Toutes les chaînes sont internées mais ... Je suis sûr que ceux qui ne sont pas stockés sur le tas.

Je ne sais pas Java

J'ai trouvé sur le site de MSDN sur le ldstr instruction IL :

  

L'instruction <=> pousse une référence d'objet (type S) à un nouvel objet de chaîne représentant la chaîne littérale spécifique stockée dans les métadonnées. L'instruction <=> alloue la quantité requise de mémoire et effectue une conversion de format requis pour convertir la chaîne littérale de la forme utilisée dans le fichier au format de chaîne requise lors de l'exécution.

     

Le Common Language Infrastructure (CLI) garantit que le résultat de deux instructions de ldstr se référant à deux jetons de métadonnées qui ont la même séquence de caractères revenir exactement le même objet chaîne (un processus appelé « chaîne interner »).

Cela implique que les chaînes littérales sont en fait stockés sur le tas dans .NET (contrairement à Java comme a souligné mmyers ).

En Java, des chaînes comme tous les objets se trouvent dans le tas. Seules les variables primitives locales (ints, chars et des références à des objets) se trouvent dans la pile.

Interné chaîne de Java sont situés dans une piscine séparée appelée la piscine String. Ce pool est maintenu par la classe de chaîne et se trouve sur le segment normal (pas la piscine Perm, comme mentionné ci-dessus, qui est utilisé pour stocker les données de classe).

Si je comprends bien pas toutes les chaînes sont interné, mais appeler myString.intern () retourne une chaîne qui est garanti à partir de la piscine String.

Voir aussi: http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally. html et la javadoc http: // java. sun.com/j2se/1.5.0/docs/api/java/lang/String.html#intern ()

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top