Java 和 .NET 字符串文字位于何处? [英] Where do Java and .NET string literals reside?

查看:37
本文介绍了Java 和 .NET 字符串文字位于何处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

A recent question about string literals in .NET caught my eye. I know that string literals are interned so that different strings with the same value refer to the same object. I also know that a string can be interned at runtime:

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

显然,在运行时驻留的字符串驻留在堆上,但我假设一个文字被放置在程序的数据段中(并在我的 回答 所述问题).但是我不记得在任何地方看到过这个.我认为是这种情况,因为这是我的做法,而且 ldstr IL 指令用于获取文字并且似乎没有分配的事实似乎支持我.

Obviously a string that is interned at runtime resides on the heap but I had assumed that a literal is placed in the program's data segment (and said so in my answer to said question). However I don't remember seeing this anywhere. I assume this is the case since it's how I would do it and the fact that the ldstr IL instruction is used to get literals and no allocation seems to take place seems to back me up.

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

To cut a long story short, where do string literals reside? Is it on the heap, the data segment or some-place I haven't thought of?

如果字符串文字do驻留在堆上,它们什么时候分配?

If string literals do reside on the heap, when are they allocated?

推荐答案

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

Strings in .NET are reference types, so they are always on the heap (even when they are interned). You can verify this using a debugger such as WinDbg.

如果你有下面的课程

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

并且您在实例上调用 Foo(),您可以使用 WinDbg 来检查堆.

And you call Foo() on an instance, you can use WinDbg to inspect the heap.

引用很可能会存储在一个小程序的寄存器中,因此最简单的方法是通过执行!dso 来找到对特定字符串的引用.这为我们提供了相关字符串的地址:

The reference will most likely be stored in a register for a small program, so the easiest is to find the reference to the specific string is by doing a !dso. This gives us the address of our string in question:

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 找出实例在哪一代:

Now use !gcgen to find out which generation the instance is in:

0:000> !gcgen 025d2d04 
Gen 0

它在第 0 代 - 即它刚刚被分配.谁在扎根?

It's in generation zero - i.e. it has just be allocated. Who's rooting it?

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[].那是实习桌.我们来看看.

The ESP is the stack for our Foo() method, but notice that we have a object[] as well. That's the intern table. Let's take a look.

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

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

I reduced the output somewhat, but you get the idea.

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

In conclusion: strings are on the heap - even when they are interned. The interned table holds a reference to the instance on the heap. I.e. interned strings are not collected during GC because the interned table roots them.

这篇关于Java 和 .NET 字符串文字位于何处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆