关于 .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来检查堆.
该引用很可能存储在一个小程序的寄存器中,因此最简单的方法是通过执行a来查找对特定字符串的引用!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
我稍微减少了输出,但你明白了.
总之:字符串在堆上 - 即使它们被实习.interned表保存对堆上实例的引用.即,在GC期间不会收集实习字符串,因为实习表会根据它们进行收集.
在Java中(来自Java词汇表):
在Sun的JVM中,实习的字符串(包括字符串文字)存储在称为perm gen的特殊RAM池中,其中JVM还加载类并存储本机编译的代码.但是,intered Strings的行为与它们存储在普通对象堆中的行为没有区别.