Где живут строковые литералы Java и .NET?
Недавний вопрос о строковых литералах в .NET попался мне на глаза. Я знаю, что строковые литералы интернированы, так что разные строки с одинаковым значением относятся к одному и тому же объекту. Я также знаю, что строка может быть интернирована во время выполнения:
string now = DateTime.Now.ToString().Intern();
Очевидно, что строка, которая интернирована во время выполнения, находится в куче, но я предположил, что литерал помещается в сегмент программных данных (и так сказал в ответе к указанному вопросу). Однако я ничего не помню. Я предполагаю, что это так, потому что это так, как я это сделал, и тот факт, что инструкция ldstr
IL используется для получения литералов, и никакое распределение, похоже, не происходит, похоже, поддерживает меня.
Короче говоря, где живут строковые литералы? Это на куче, сегменте данных или на каком-то месте, о котором я не думал?
Изменить: Если строковые литералы находятся в куче, когда они выделяются?
Ответы
Ответ 1
Строки в .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, потому что интернированный стол их коренит.
Ответ 2
В Java (из Java Glossary):
В Sun JVM интернированные строки (включая струнные литералы) хранятся в специальном пуле ОЗУ, называемом perm gen, где JVM также загружает классы и хранит изначально скомпилированный код. Однако промежуточные строки ведут себя не иначе, как если бы они были сохранены в обычной куче объектов.
Ответ 3
Исправьте меня, если я ошибаюсь, но не все объекты находятся в куче, как на Java, так и на .NET?
Ответ 4
В .Net строковые литералы, "интернированные", хранятся в специальной структуре данных, называемой "intern table". Это отдельно от кучи и стека. Однако не все строки интернированы... Я уверен, что те, которые не хранятся в куче.
Не знаю о Java
Ответ 5
Я нашел это на сайте MSDN в ldstr
инструкция IL:
Команда ldstr
подталкивает ссылку на объект (тип O) на новый строковый объект, представляющий конкретный строковый литерал, хранящийся в метаданных. Команда ldstr
выделяет требуемый объем памяти и выполняет любое преобразование формата, необходимое для преобразования строкового литерала из формы, используемой в файле, в строковый формат, необходимый во время выполнения.
Общая языковая инфраструктура (CLI) гарантирует, что результат двух команд ldstr, относящихся к двум токенам метаданных, которые имеют одну и ту же последовательность символов, возвращает точно тот же строковый объект (процесс, известный как "интернирование строк" ).
Это означает, что строковые литералы фактически хранятся в куче в .NET(в отличие от Java как указано mmyers).
Ответ 6
В Java строки, подобные всем объектам, находятся в куче.
Только локальные примитивные переменные (ints, chars и ссылки на объекты) находятся в стеке.
Ответ 7
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()