logo 广告
Loading...
 导航 所在位置:论坛首页 -> ┈┋电脑网络┋┈ -> Asp/Asp.Net教程 -> 在.NET程序中正确使用String类型
回复
标题:在.NET程序中正确使用String类型收藏 编辑 删除 楼主 | 上一篇 下一篇
晕菜两次
头像
等级:社区游民
权限:普通用户
积分:13
金钱:213
声望:16
经验:16
发帖数:47
注册:2008年4月20日
资料 短消息2008-4-26 11:38:40
在实际程序中,String类型用得非常广泛,然而,由于.NET对String类型变量的独特管理方式,使用不当,会严重影响程序的性能。我们分几个方面来谈这个问题:

  1、了解String数据的内存分配方式

  编写一个控制台应用程序,输入以下测试代码:

  class Program
  {
  static void Main(string[] args)
   {
  String s = "a";
  s = "abcd";
  }
  }

  使用.NET Framework 2.0 SDK提供的ildasm.exe工具查看生成的MSIL指令:
  01 .method private hidebysig static void Main(string[] args) cil managed
  02 {
  03 .entrypoint
  04 // 代码大小 14 (0xe)
  05 .maxstack 1
  06 .locals init ([0] string s)
  07 IL_0000: nop
  08 IL_0001: ldstr "a"
  09 IL_0006: stloc.0
  10 IL_0007: ldstr "abcd"
  11 IL_000c: stloc.0
  12 IL_000d: ret
  13 } // end of method Program::Main
  DL@bitsCN_com网管软件下载

  简要解释一下上述MSIL指令代码:

  第06句给局部变量s分配一个索引号(索引号从0开始,如函数中有多个局部变量,其索引号按在函数中出现的顺序加一)。

  在编译时编译器会将代码中的两个字串“a”和“abcd”写入到程序集的元数据(metadata)中,此时,这两个字串被称为“字串字面量(string literal)”。

  第08句使用ldstr指令为字串对象“a”分配内存,并将此对象引用压入到线程堆栈中。

  第09句使用stloc指令从线程堆栈顶弹出先前压入的对象引用,将其传给局部变量s(其索引号为0)。

  同样的过程对“abcd”重复进行一次,所以这两句简单的代码

String s = "a";
s = "abcd";

  将会导致CLR使用ldstr指令分配两次内存。

  根据上述分析,读者一定明白了String变量的内容是只读的,给其赋不同的值将会导致内存的重新分配。因此,为提高程序性能,编程时应尽量减少内存的分配操作。

  下面对代码中常见的字串用法进行分析,从中读者可以知道如何避免严重影响程序性能的字串操作。
bbs.bitsCN.com

  2、尽量少使用字串加法运算符

  请看以下两段代码:

  (1) String s1 = "ab";
s1+="cd";

  (2) String s1="ab"+"cd";

  这两段代码运行结果一样,但速度一样快吗?

  请看第(1)段代码生成的MSIL指令:


  .locals init ([0] string s1)
  IL_0000: nop
  IL_0001: ldstr "ab"
  IL_0006: stloc.0
  IL_0007: ldloc.0
  IL_0008: ldstr "cd"
  IL_000d: call string [mscorlib]System.String::Concat(string,
  string)
  IL_0012: stloc.0
  IL_0013: ret

  再看第(2)段代码生成的指令:


  .locals init ([0] string s1)
  IL_0000: nop
  IL_0001: ldstr "abcd"
  IL_0006: stloc.0
  IL_0007: ret

  可以很清楚地看到,第(1)段代码将导致String类的Concat()方法被调用(实现字串加法运算)。对于第(2)段代码,由于C#编译器聪明地在编译时直接将两个字串合并为一个字串字面量,所以程序运行时CLR只调用一次ldstr指令就完成了所有工作,其执行速度谁快就不言而喻了!

  3、避免使用加法运算符连接不同类型的数据

  请看以下代码:

  bitsCN#com中国网管联盟

  String str = "100+100=" + 200;
  Console.Writeline(str);

  生成的MSIL指令为:

  .maxstack 2
  .locals init ([0] string str)
  IL_0000: nop
  IL_0001: ldstr "100+100="
  IL_0006: ldc.i4 0xc8
  IL_000b: box [mscorlib]System.Int32
  IL_0010: call string [mscorlib]System.String::Concat(object,
  object)
  IL_0015: stloc.0
  IL_0016: ldloc.0
  IL_0017: call void [mscorlib]System.Console::WriteLine(string)
  IL_001c: nop
  IL_001d: ret

  可以清晰地看到,这两句C#代码不仅导致了String类的Concat()方法被调用(IL_0010),而且还引发了装箱操作(IL_000b)!
Concat()方法会导致CLR为新字串分配内存空间,而装箱操作不仅要分配内存,还需要创建一个匿名对象,对象创建之后还必须有一个数据复制的过程,代价不菲!

  改为以下代码:

  String str = "100+100=";
  bitsCN.nET*中国网管博客

  Console.Write(str);
  Console.WriteLine(200);

  生成的MSIL指令为:

  .maxstack 1
  .locals init ([0] string str)
  IL_0000: nop
  IL_0001: ldstr "100+100="
  IL_0006: stloc.0
  IL_0007: ldloc.0
  IL_0008: call void [mscorlib]System.Console::Write(string)
  IL_000d: nop
  IL_000e: ldc.i4 0xc8
  IL_0013: call void [mscorlib]System.Console::WriteLine(int32)
  IL_0018: nop
  IL_0019: ret

  可以看到,虽然多了一次方法调用(Console.Write)方法,但却避免了复杂的装箱操作,也避免了调用String.Concat()方法对内存的频繁分配操作,性能更好。

  4.在循环中使用StringBuilder代替String实现字串连接

  在某些场合需要动态地将多个子串连接成一个大字串,比如许多复杂的SQL命令都是通过循环语句生成的。这时,应避免使用String类的加法运算符,举个简单的实例:

  String str ="";
  bitsCN~com

  for (int i = 1; i <= 10; i++)
  {
  str += i;
  if(i<10)
  str += "+";
  }

  上述代码将生成一个字串:1+2+…+10。

  有了前面的知识,读者一定知道这将导致进行10次装箱操作,19次字串内存分配操作(由String.Concat()方法引发),由于生成的MSIL指令太长,此处不再列出,请读者自行用ildasm.exe工具查看上述代码生成的MSIL指令。

  改为以下代码,程序性能会好很多:

  //预先分配1K的内存空间
  StringBuilder sb = new StringBuilder(1024);
  for (int i = 1; i <= 10; i++)
  {
  sb.Append(i);
  if(i<10)
  sb.Append("+");
  }
  String result = sb.ToString();

  通过使用ildasm.exe工具查看生成的MSIL代码,发现虽然上述代码生成的MSIL指令比前面多了7条,但却避免了耗时的装箱操作,而且内存分配的次数也少了很多。当循环的次数很大时,两段代码的运行性能差异很大。

签名

2008-4-26 11:38:40 顶部
第1页 共页 共0个回复     <<    >>    
 快速回复
  • 支持UBB,HTML标签

  • 高级回复

  • 操作选项:评分 加精 解精 奖惩 设专题 设公告 解公告 固顶 总固顶 解固顶 结帖 解结帖 锁帖 解锁 移帖 删帖
      首页 | 购买指南 | 虚拟主机 | 特色介绍 | 下载中心 | 支付方式
    Copyright 2004-2008 BBSGood.com Powered By: BBSGood.Speed Version 5.0
      咨询电话:0575-85513832、0575-85513825(传真)、7*24小时咨询服务:13606552007 不良信息举报中心 浙ICP备05029817号
      业务QQ:38958768、客服QQ1:415896239、客服QQ2:343896043、MSN:jccsxx@hotmail.com