Где Java and.NET строковые литералы находятся?

недавно вопрос о строковых литералов в .NET поймал мой взгляд. Я знаю, что строковые литералы интернированы чтобы разные строки с одинаковым значением ссылались на один и тот же объект. Я также знаю, что строка может быть интернирована во время выполнения:

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

очевидно, что строка, которая интернирована во время выполнения, находится в куче, но я предположил, что литерал помещен в сегмент данных программы (и сказал это в моем ответ чтобы сказал вопрос.) Однако я не помню такого нигде. Я предполагаю, что это так, поскольку это то, как я бы это сделал, и тот факт, что ldstr Il инструкция используется для получения литералов, и никакое распределение, кажется, не имеет места, кажется, поддерживает меня.

короче говоря, где находятся строковые литералы? Это в куче, сегменте данных или в каком-то месте, о котором я не думал?


Edit: если строковые литералы do находятся на куча, когда они распределяются?

7 ответов


строки в .NET являются ссылочными типами, поэтому они всегда находятся в куче (даже когда они интернированы). Вы можете проверить это с помощью отладчика, такие как WinDbg.

если у вас есть класс ниже

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

и это вы называете Foo() в экземпляре вы можете использовать WinDbg для проверки кучи.

ссылка, скорее всего, будет храниться в регистре для небольшой программы, поэтому проще всего найти ссылку на конкретную строку, выполнив !dso. Это дает нам адрес нашей строки:

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[])

теперь использовать !gcgen чтобы узнать, в каком поколении находится экземпляр:

0:000> !gcgen 025d2d04 
Gen 0

он находится в нулевом поколении-т. е. он только что был выделен. Кто болел этим?

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)

ESP-это стек для нашего Foo() метод, но обратите внимание, что у нас есть object[] как хорошо. Это стол интерна. Давайте посмотрим.

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

я несколько уменьшил выход, но вы получаете идея.

в заключение: строки в куче - даже когда они интернированы. Интернированных таблица содержит ссылку на экземпляр в куче. Т. е. интернированные строки не собираются во время GC, потому что интернированная таблица укореняет их.


в Java (с Java Glossary):

в JVM Sun интернированные строки (которые включают строковые литералы) хранятся в специальном пуле ОЗУ, называемом perm gen, где JVM также загружает классы и хранит скомпилированный код. Однако взаимодействующие строки ведут себя не иначе, чем если бы они хранились в обычной куче объектов.


исправьте меня, если я ошибаюсь, но не все объекты находятся в куче, как в Java, так и в .NET?


в .Net строковые литералы при " интернировании "хранятся в специальной структуре данных, называемой"таблица интернов". Это отдельно от кучи и стека. Однако не все строки интернированы... Я уверен, что те, которые не хранятся в куче.

Не знаю о Java


Я нашел это на сайте MSDN о ldstr Ил инструкция:

на ldstr инструкция помещает ссылку на объект (тип O) в новый строковый объект, представляющий конкретный строковый литерал, хранящийся в метаданных. The ldstr - инструкции выделяет необходимый объем памяти и выполняет любое преобразование формата, необходимое для преобразования строкового литерала из формы, используемой в файле, в строковый формат, требуемый в во время выполнения.

инфраструктура общего языка (CLI) гарантирует, что результат двух инструкций ldstr, ссылающихся на два маркера метаданных, которые имеют одинаковую последовательность символов, возвращает точно такой же строковый объект (процесс, известный как "String interning").

это означает, что строковые литералы фактически хранятся в куче в .NET (в отличие от Java как указал by mmyers).


в Java строки, как и все объекты, находятся в куче. В стеке находятся только локальные примитивные переменные (ints, chars и ссылки на объекты).


интернированные строки в java расположены в отдельном пуле, называемом пулом строк. Этот пул поддерживается строковым классом и находится в обычной куче (а не в пуле Perm, как указано выше, который используется для хранения данных класса).

Как я понимаю, не все строки интернированы, но вызов myString.intern () возвращает строку, которая гарантируется из пула строк.

посмотреть также: http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html и в Javadoc http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html#intern()