Вопрос

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

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

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

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


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

Это было полезно?

Решение

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

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

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

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

Не знаю о Java

Я нашел это на сайте MSDN о ldstr IL instruction:

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

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

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

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

Интернированные строки в 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 ()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top