java - Java 和 .NET 字符串文字驻留在哪里?

标签 java .net string-literals string-table

最近的 question about string literals在 .NET 中引起了我的注意。我知道字符串文字是 interned以便具有相同值的不同字符串引用相同的对象。我也知道可以在运行时实习字符串:

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

显然,在运行时实习的字符串驻留在堆上,但我假设将文字放置在程序的数据段中(并在我的 answer 中对上述问题说过)。但是我不记得在任何地方看到过这个。我认为是这种情况,因为我会这样做,并且 ldstr IL 指令用于获取文字并且似乎没有发生分配的事实似乎支持了我。

长话短说,字符串字面量在哪里?是在堆上、数据段上还是我没想到的地方?


编辑:如果字符串文字确实驻留在堆上,它们是什么时候分配的?

最佳答案

.NET 中的字符串是引用类型,因此它们总是在堆上(即使它们被实习)。您可以使用诸如 WinDbg 之类的调试器来验证这一点。

如果你有以下类(class)

   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

我稍微减少了输出,但你明白了。

结论:字符串在堆上——即使它们被实习。实习表保存对堆上实例的引用。 IE。在 GC 期间不会收集实习字符串,因为实习表将它们作为根。

关于java - Java 和 .NET 字符串文字驻留在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/372547/

相关文章:

javascript - 以字符串形式内部化字符串文字

c# - 检查列表中是否存在值 - 比循环更好的方法?

c# - 为什么一路往下用Async/await

java - 对同一类中方法的无参数调用产生 NullPointerException

Java Web Start 和安全

c# - c0000005 C 中的异常 :\Windows\Microsoft. NET\Framework\v4.0.30319\sos.threads 调试器扩展

c++ - 指针和字符串文字

c - 为什么我可以更新指向(常量)字符串文字的指针?

java - 调用构造函数的设计模式

java - 将 array_chunk 从 php 转换为 java