浅谈C#中的string驻留池

2020-06-24 18:02:40刘景俊

可以看到,果然是System.String对象,这就和我的图是相符的。

二 驻留池的验证

1. String下的驻留池验证方法

很遗憾的是水平有限,由于驻留池既不在堆中也不在栈上,目前还不知道怎么用windbg去打印CLR中驻留池字典内容,不过也可以通过 string.Intern 去验证。

    //
    // Summary:
    //   Retrieves the system's reference to the specified System.String.
    //
    // Parameters:
    //  str:
    //   A string to search for in the intern pool.
    //
    // Returns:
    //   The system's reference to str, if it is interned; otherwise, a new reference
    //   to a string with the value of str.
    //
    // Exceptions:
    //  T:System.ArgumentNullException:
    //   str is null.
    [SecuritySafeCritical]
    public static String Intern(String str);

从注释中可以看到,这个方法的意思就是:如果你定义的str在驻留池中存在,那么就返回驻留池中命中内容的堆上引用地址,如果不存在,将新字符串插入驻留池中再返回堆上引用,先上一下代码:

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      //验证nihao是否在驻留池中,如果存在那么str3 和 str1,str2一样的引用
      var str3 = string.Intern("nihao");

      //验证新的字符串内容是否进入驻留池中
      var str4 = string.Intern("cnblogs");
      var str5 = string.Intern("cnblogs");

      Console.ReadLine();
    }

接下来分别验证一下str3是否也是和str1和str2一样的引用,以及str5是否存在驻留池中。

ConsoleApp2.Program.Main(System.String[]) [C:dreamCsharpConsoleApp1ConsoleApp2Program.cs @ 37]
  LOCALS:
    0x00000047105fea58 = 0x0000018537312d48
    0x00000047105fea50 = 0x0000018537312d48
    0x00000047105fea48 = 0x0000018537312d48
    0x00000047105fea40 = 0x0000018537312d70
    0x00000047105fea38 = 0x0000018537312d70

从五个变量地址中可以看到,nihao已经被str1,str2,str3共享,cnblogs也进入了驻留池中实现了共享。

2. 运行期相同string是否进入驻留池

这里面有一个坑,前面讨论的相同字符串都是在编译期就知道的,但运行时中的相同字符串是否也会进入驻留池呢? 这是一个让人充满好奇的话题,可以试一下,在程序运行时接受IO输入内容hello,看看是否和str1,str2共享引用地址。

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      var str3 = Console.ReadLine();

      Console.WriteLine("输入完成!");
      Console.ReadLine();
    }

0:000> !clrstack -l
000000f6d35fee50 00007ff889e7090d *** WARNING: Unable to verify checksum for ConsoleApp2.exe
ConsoleApp2.Program.Main(System.String[]) [C:dreamCsharpConsoleApp1ConsoleApp2Program.cs @ 33]
  LOCALS:
    0x000000f6d35fee98 = 0x000002cb1a552d48
    0x000000f6d35fee90 = 0x000002cb1a552d48
    0x000000f6d35fee88 = 0x000002cb1a555f28
0:000> !do 0x000002cb1a555f28
Name:    System.String
MethodTable: 00007ff8e7a959c0
EEClass:   00007ff8e7a72ec0
Size:    36(0x24) bytes
File:    C:WINDOWSMicrosoft.NetassemblyGAC_64mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll
String:   nihao
Fields:
       MT  Field  Offset         Type VT   Attr      Value Name
00007ff8e7a985a0 4000281    8     System.Int32 1 instance        5 m_stringLength
00007ff8e7a96838 4000282    c     System.Char 1 instance        6e m_firstChar
00007ff8e7a959c0 4000286    d8    System.String 0  shared      static Empty
                >> Domain:Value 000002cb18ad39f0:NotInit <<