Где находятся строковые литералы Java и .NET? - PullRequest
28 голосов
/ 16 декабря 2008

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

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

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

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


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

Ответы [ 7 ]

107 голосов
/ 16 декабря 2008

Строки в .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

Я немного уменьшил вывод, но вы поняли идею.

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

12 голосов
/ 16 декабря 2008

На Java (из Глоссарий Java ):

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

3 голосов
/ 16 декабря 2008

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

1 голос
/ 17 декабря 2008

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

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

Common Language Infrastructure (CLI) гарантирует, что результат двух инструкций ldstr, относящихся к двум токенам метаданных, которые имеют одинаковую последовательность символов, возвращает точно один и тот же строковый объект (процесс, известный как «интернирование строк»).

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

1 голос
/ 16 декабря 2008

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

Не знаю о Java

0 голосов
/ 17 декабря 2008

Interned String в java расположены в отдельном пуле, называемом String Pool. Этот пул поддерживается классом String и находится в обычной куче (не в пуле 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()

0 голосов
/ 16 декабря 2008

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

...