Java和.NETstring文字在哪里?

最近一个关于 .NET string文字的问题引起了我的注意。 我知道,string文字是interned使不同的string具有相同的值引用同一个对象。 我也知道一个string可以在运行时被实现:

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

显然,一个在运行时被实现的string驻留在堆上,但是我认为文字被放置在程序的数据段中(并且在我对所述问题的回答中这样说)。 但是我不记得在任何地方看到这个。 我认为这是事实,因为它是如何做到这一点,事实上, ldstr IL指令是用来得到文字,似乎没有分配似乎发生了。

长话短说,string文字在哪里? 它是在堆,数据段还是我没有想到的某个地方?


编辑:如果string文字驻留在堆上,他们什么时候分配?

.NET中的string是引用types,所以它们总是堆在一起(即使它们被实现)。 您可以使用诸如WinDbg之类的debugging器来validation这一点。

如果你有下面的课程

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

而且你在一个实例上调用Foo() ,你可以使用WinDbg来检查这个堆。

引用很可能会存储在一个小程序的寄存器中,所以最简单的方法是通过执行!dso来查找对特定string的引用。 这给我们的问题的string的地址:

 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 

我减less了一些输出,但你明白了。

总而言之 ,即使是在实习期间,弦乐也是如此。 实参表持有对堆上实例的引用。 即,interestring不在GC期间收集,因为interned表的根源。

在Java中(来自Java术语表 ):

在Sun的JVM中,被拦截的string(包括string文字)被存储在称为perm gen的特殊RAM池中,JVM也加载类并存储本机编译的代码。 但是,被交织的string与存储在普通对象堆中的行为没有区别。

纠正我,如果我错了,但不是所有的对象驻留在堆,在Java和.NET?

在.Net中,“interned”时的string文字被存储在一个称为“intern table”的特殊数据结构中。 这与堆和堆栈是分开的。 并不是所有的string都被拦截,但是我确定那些不是被存储在堆中的。

不了解Java

我在MSDN网站上发现了关于ldstr IL指令的这个问题 :

ldstr指令将对象引用(typesO)推送到表示存储在元数据中的特定string文字的新string对象。 ldstr指令分配必需数量的内存,并执行所需的任何格式转换,以将string文本从文件中使用的表单转换为运行时所需的string格式。

公共语言基础结构(CLI)保证两条ldstr指令的引用两个具有相同字符序列的元数据标记的结果精确地返回相同的string对象(一个称为“string入门”的过程)。

这意味着string文字实际上存储在.NET中的堆中(与mmyers 指出的 Java不同)。

在Java中,像所有对象的string都驻留在堆中。 只有本地原始variables(整数,字符和对象的引用)驻留在堆栈中。

java中的Interned String's位于一个名为String Pool的独立Pool中。 该池由String类维护,驻留在普通的Heap(不是上面提到的用于存储类数据的Perm池)。

据我了解,并不是所有的string都被拦截,但是调用myString.intern()会返回一个String保证的string。

另请参阅: http : //www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html和javadoc http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String html的#实习生()