实例讲解.NET字符串拘留池

开发 后端
本文是从一道面试题引出的例子,提到了.NET字符串拘留池。我们希望通过本实例让大家更好的了解拘留池的概念。

本文将从.NET字符串拘留池讲起,希望大家在今后碰到这样的问题时,能正确处理。公共语言运行库通过维护一个表来存放字符串,该表称为拘留池,它包含程序中以编程方式声明或创建的每个唯一的字符串的一个引用.因此,具有特定值的字符串的实例在系统中只有一个。

XiaoMing在博客园上发表的《年前的面试经历(二) 》中回贴众多,其中谈到一个面试题:string a = "a" + "b"到底分配几次内存。

这涉及到CLR内部的.NET字符串拘留池(string interning pool)问题。

网友 Ivony和 横刀天笑的回贴引用资料指出拘留池是进程范围内的,因此,有可能以下定义字串常量的代码不会导致分配两次内存——因为另一个进程可能已经在拘留池中创建了“a”或 “ab”这两个字串对象。

  1. string s1 = "a";  
  2. string s2 = "a";  
  3. string s3 = "a" + "b";  
  4. Console.WriteLine(s1);  
  5. Console.WriteLine(s2);  
  6. Console.WriteLine(s3); 

我对此结论有点怀疑,于是到Google和MSDN中查找,发现.NET字符串拘留池的有关资料很混乱。***决定自己编程作实验。

String类有一个IsInterned()方法用于检测一个字串是否在拘留池中,另一个Intern()方法用于将一个字串加入拘留池中。

为此,我写了以下测试代码:

  1. class Program  
  2.     {  
  3.         //static string outerstr = "j";    
  4.          
  5.         static void Main(string[] args)  
  6.         {  
  7.              
  8.             string str = new string('j',1);  //动态构建的字串,不会放到拘留池中  
  9.             if (string.IsInterned(str) == null)  
  10.                 Console.WriteLine(str + " is not interned");   //不在拘留池  
  11.             else  
  12.                 Console.WriteLine(str+ " is interned"); //在拘留池  
  13.  
  14.             Console.ReadKey();  
  15.             string s = string.Intern(str);  //强制加入拘留池  
  16.           //再次检测  
  17.            if (string.IsInterned(str) == null)  
  18.                 Console.WriteLine(str + "is not interned");  
  19.             else  
  20.                 Console.WriteLine(str+ " is interned");  
  21.             Console.ReadKey();             
  22.         } 

上述代码运行结果如下:

  1. j is not interned  
  2. j is interned 


不管你运行多少次,也不管你是否同时运行多个此程序的实例,始终结果是一致的,都是上面的结果。这说明进程结束后,字串拘留池中的与此进程所装载的程序集相关的字串常量对象被清除。

现在取消对outerstr 变量的注释,结果变为:

  1. j is interned  
  2. j is interned 


这说明程序集中的常量“j”在装载时被加入到了字串拘留池中,所以才有上述结果。

还有一个问题,字串拘留池中的对象能否跨越不同进程边界共享?

编写另一个测试程序:

  1. class Program  
  2.    {  
  3.          
  4.        static void Main(string[] args)  
  5.        {  
  6.  
  7.            string str = new string('j', 1);  
  8.            Console.WriteLine(string.IsInterned(str)==null);    
  9.            Console.ReadKey();  
  10.        }  
  11.    } 

不管前一个测试程序是否在运行,上述代码始终输出true,说明“j”这个字串没有在拘留池中,此进程无法获取另一个进程追加到字串拘留池中的“j”字串。

从这些实验是否可以得出以下结论?

当进程运行结束,此进程所加载的程序集中所定义的字串常量对象会被CLR从字串拘留池中移除。

因此,CLR字串拘留池中的字串常量是“进程和程序集相关”的。

应用程序所定义的字串常量对象在应用程序域装载程序集时被加入到字串拘留池中。

所以,字串拘留池中的字串对象不能跨进程共享。不然,我们如何解释代码运行的结果?

由于同一进程中可以创建多个应用程序域,我还没有编写代码测试字串拘留池中的字串对象是否可以在属于同一进程的多个应用程序域共享。此问题留待进一步探索。

有无高人能彻底解释清楚这一问题?

补充:

我的测试环境是Windows 7 + Visual Studio 2010 RC.

原文标题:探讨一下.NET字串拘留池

链接:http://www.cnblogs.com/bitfan/archive/2010/03/02/1676733.html

【编辑推荐】

  1. .NET Framework字符串相关操作细节介绍
  2. 详解.NET字符串解析的具体过程
  3. 改进C#连接字符串的性能
  4. .NET Lambda表达式的语义:字符串列表范例
  5. C#字符串的几种常用方法
责任编辑:彭凡 来源: 博客园
相关推荐

2024-04-01 08:41:39

字符串.NET

2009-12-24 09:49:02

ADO.Net连接池

2009-11-30 14:08:42

PHP字符串原理

2010-02-02 11:27:16

C++字符串

2011-07-21 15:36:40

JAVA

2009-12-15 13:15:11

Ruby字符串

2010-09-13 15:06:40

sql server字

2024-03-04 15:05:37

2012-11-12 09:26:06

.NET多线程

2015-11-16 10:24:45

Java常量池字符串

2009-12-24 10:06:30

ADO.NET字符串

2010-01-06 10:07:35

.NET Framew

2015-10-27 09:41:16

Javaintern

2010-11-25 15:59:33

字符串.NET

2009-10-13 16:09:27

.NET字符串解析

2009-11-12 11:09:56

ADO.NET连接字符

2009-10-16 13:04:57

VB.NET字符串数组

2009-11-26 13:52:07

PHP字符串替换函数s

2009-09-01 17:41:53

C#截取字符串函数

2011-06-22 18:08:01

Qt TCP 字符串
点赞
收藏

51CTO技术栈公众号