代码改变世界

.net 垃圾回收学习[NET 2.0 Performance Guidelines - String Operations]【翻译&&学习】

2011-08-28 18:33  一一九九  阅读(240)  评论(0编辑  收藏  举报

From: http://www.guidanceshare.com/wiki/.NET_2.0_Performance_Guidelines_-_String_Operations

目录:

Avoid Inefficient String Concatenation


过多的字符串连接会导致很多的内存分配和释放操作,因为每次你做一个操作去修改字符串的时候,一个新的字符床被创建,之前的字符串随后成为了垃圾回收的目标。

  • 如果你进行字符串的字面常量连接操作,编译器会在编译的时候就进行连接操作。

    //'Hello' and 'world' are string literals
    String str = "Hello" + "world";
  • 如果你进行的不是字符串字面常量连接,CLR将会在运行时期进行连接,所以使用+运算符将会在托管堆上创建多个字符串对象。
  • 当你需要连接字符床多次的时候使用StringBuilder进行复杂的字符串操作

    // using String and '+' to append
    String str = "Some Text";
    for ( ... loop several times to build the string ...) {
      str = str + " additional text ";
    }
    // using String and .Append method to append
    StringBuilder strBuilder = new StringBuilder("Some Text ");
    for ( ... loop several times to build the string ...) {
      strBuilder.Append(" additional text ");
    }

Use + when the number of Appends Is Known


假如你知道需要进行连接操作的字符串的数量,那么尽量使用+进行字符床连接操作。

String str = str1+str2+str3;

假如你在一个表达式中进行字符串的链接操作,只需要调用一次String.Contact即可。它不会产生任何临时的字符串(为了进行字符串拼接操作而产生的临时字符串)。注意:你不应该在一个循环中采用+运算符操作,使用StringBuilder。

Use StringBuilder When the Number of Appends Is Unknown


假如你不知道需要添加的字符串数量,可能是通过一个循环进行遍历或者构造一个动态的SQL查询,使用StringBuilder Class。代码如下:

for (int i=0; i< Results.Count; i++)
{
  StringBuilder.Append (Results[i]);
}  

StringBuilder创建的时候初始容量是16。小于初始容量的字符串被存储在StringBuilder对象中。最初的容量大小可以通过构造函数进行设置:

public StringBuilder (int capacity);

当你消耗完最初分配的缓存后你可以持续进行字符串连接操作而不需要额外的内存分配。因此,使用StringBuilder对象比使用String对象要更有效率。假如你随后继续进行连接,StringBuilder会创建一个2倍于当前大小的新的的缓冲区。所以当你使用StringBuilder的时候,如果超出了最初的16个的大小,StringBuilder会重新分配一个32的Buffer并且复制老的字符串到新的Buffer中。老的Buffer变得访问不到并且成为了垃圾回收的候选。

注意你需要设置StringBuilder的最初大小为一个优化的值来降低新的对象的大小。为了决定你的情况的合适的大小,最好的方式是通过CLR profiler来跟踪内存的消耗情况。 For more information about how to use CLR profiler, see "How To: Use CLR Profiler" at http://msdn.microsoft.com/library/en-us/dnpag/html/scalenethowto13.asp

Treat  StringBuilder as an Accumulator


你可以把StringBuilder当作一个累加器或者可以重复使用的Buffer。在进行多次的添加操作的时候StringBuilder可以避免临时字符串的分配操作。适用的场景如下:

  • 连接字符床。当使用StringBuilder的时候你应该使用如下的方法进行字符串连接操作。

    StringBuilder sb;
    sb.Append(str1);
    sb.Append(str2);

而不要使用下面的代码进行字符串连接操作

sb.Append(str1+str2);

这是因为你不需要一个临时字符串先进行Str1和Str2的连接操作。

  • 从不同的函数函数连接字符串。示例如下:

    StringBuilder sb;
    sb.Append(f1(…));
    sb.Append(f2(…)); 
    sb.Append(f3(…));

      之前的代码片段当函数返回的时候会产生临时的字符串分配操作,你可以通过以下的模式避免临时的字符串分配操作

void f1( sb,…);
void f2( sb,…);
void f3( sb,…);

在这种情况下,StringBuilder实例直接被当作参数传递,Sb.Append直接在函数的内部被调用,避免了临时的字符串分配。

Use the Overloaded Compare Methon for Case-Insensitive String Comparisons


当你进行字符串操作的时候需要小心,避免使用ToLower等方法,因为这种方式你会创建新的临时字符串。

// Bad way for insensitive operations because ToLower creates temporary 
strings
String str="New York";
String str2 = "New york";
if (str.ToLower()==str2.ToLower())
  // do something

比较有效地方式是Compare方法进行字符串的比较

str.Compare(str,str2,false);

Note The String.Compare method uses the info in the CultureInfo.CompareInfo property to compare culture-sensitive strings.