Мое внимание привлек недавний вопрос о строковых литералах в .NET. Я знаю, что строковые литералы - это интернированный, поэтому разные строки с одинаковым значением относятся к одному и тому же объекту. Я также знаю, что строку можно интернировать во время выполнения:
string now = DateTime.Now.ToString().Intern();
Очевидно, что строка, интернированная во время выполнения, находится в куче, но я предполагал, что литерал помещается в сегмент данных программы (и сказал об этом в моем отвечать к указанному вопросу). Однако я не помню, чтобы нигде этого видел. Я предполагаю, что дело обстоит именно так, поскольку я бы сделал это именно так, и тот факт, что инструкция ldstr IL используется для получения литералов, а распределение, похоже, не происходит, похоже, поддерживает меня.
Короче говоря, где находятся строковые литералы? Это в куче, в сегменте данных или в другом месте, о котором я не подумал?
Редактировать: Если строковые литералы делать находятся в куче, когда они выделяются?




Поправьте меня, если я ошибаюсь, но не все ли объекты находятся в куче, как в Java, так и в .NET?
Верно, я бы исключил типы значений из категории "объект", но опять же, я привык к Java, а не к .NET.
Если типы значений достаточно малы, они могут быть даже не в стеке, а только в регистрах.
Строки в .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
Я немного уменьшил производительность, но вы поняли идею.
В заключении: строки находятся в куче, даже если они интернированы. Интернированная таблица содержит ссылку на экземпляр в куче. Т.е. интернированные строки не собираются во время сборки мусора, потому что интернированная таблица их корни.
В .Net строковые литералы, когда они «интернированы», хранятся в специальной структуре данных, называемой «внутренней таблицей». Это отдельно от кучи и стека. Однако не все строки интернированы ... Я почти уверен, что те, которые не хранятся в куче.
Не знаю о Java
Конечно, внутренняя таблица просто содержит ссылки на строки и не хранит фактические байты, составляющие строку?
Интернированная таблица содержит ссылки на строки в куче.
В Java (из Глоссарий Java):
In Sun’s JVM, the interned Strings (which includes String literals) are stored in a special pool of RAM called the perm gen, where the JVM also loads classes and stores natively compiled code. However, the intered Strings behave no differently than had they been stored in the ordinary object heap.
Необходимо найти нормативную ссылку. Вы не можете просто цитировать или цитировать произвольный интернет-мусор.
В Java строки, как и все объекты, находятся в куче. В стеке находятся только локальные примитивные переменные (целые числа, символы и ссылки на объекты).
Я нашел это на сайте MSDN о Инструкция ldstr IL:
The
ldstrinstruction pushes an object reference (type O) to a new string object representing the specific string literal stored in the metadata. Theldstrinstruction allocates the requisite amount of memory and performs any format conversion required to convert the string literal from the form used in the file to the string format required at runtime.The Common Language Infrastructure (CLI) guarantees that the result of two ldstr instructions referring to two metadata tokens that have the same sequence of characters return precisely the same string object (a process known as "string interning").
Это означает, что строковые литералы фактически хранятся в куче в .NET (в отличие от Java как указал от mmyers).
нет, он только говорит, что они ведут себя так же, как если бы они хранились в обычной куче
Интернированные строки в java расположены в отдельном пуле, называемом пулом строк. Этот пул поддерживается классом String и находится в обычной куче (а не в пермском пуле, как упоминалось выше, который используется для хранения данных класса).
Насколько я понимаю, не все строки интернированы, но вызов 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 ()
В случае буквальных строк он поддерживается компилятором и загрузчиком классов. Когда-то это действительно было в PermGen.
Типы значений в .NET находятся в стеке, если они не являются частью ссылочного типа, и в этом случае они находятся в куче.