【问题标题】:string.replace vs StringBuilder.replace for memory [duplicate]string.replace vs StringBuilder.replace 内存[重复]
【发布时间】:2013-05-08 12:31:26
【问题描述】:

我已经下载了一个大约 36MB 的 byte[] 'raw' 流。然后我将其转换为字符串与

string temp = System.Text.Encoding.UTF8.GetString(raw)

然后我需要将所有“\n”替换为“\r\n”所以我尝试了

 string temp2 = temp.Replace("\n","\r\n")

但它引发了“内存不足”异常。然后我尝试使用 StringBuilder 创建一个新字符串:

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString()

它没有抛出异常。为什么首先会出现内存问题(我这里只处理 36MB),还有为什么 StringBuilder.Replace() 在另一个不工作的情况下工作?

【问题讨论】:

  • 我看到了这个问题,但它更多地与性能有关,而不是内存使用。此外,这更像是“幕后发生了什么?”问题比“我该如何解决?”一。

标签: c# replace stringbuilder


【解决方案1】:

使用时:

string temp2 = temp.Replace("\n","\r\n")

对于字符串 temp 中的每一个匹配“\n”,系统都会创建一个带有替换的新字符串。

使用 StringBuilder 不会发生这种情况,因为 StringBuilder 是可变的,因此您实际上可以修改同一个对象而无需创建另一个对象。

示例:

temp = "test1\ntest2\ntest3\n"

使用第一种方法(字符串)

string temp2 = temp.Replace("\n","\r\n")

等价于

string aux1 = "test1\r\ntest2\ntest3\n"
string aux2 = "test1\r\ntest2\r\ntest3\n"
string temp2 = "test1\r\ntest2\r\ntest3\r\n"

使用Secon方法(StringBuilder)

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString()

等价于

Stringbuilder aux = "test1\ntest2\ntest3\n"
aux = "test1\r\ntest2\ntest3\n"
aux = "test1\r\ntest2\r\ntest3\n"
aux = "test1\r\ntest2\r\ntest3\r\n"
string temp2 = aux.toString()

【讨论】:

  • 所以如果我的字符串是 36MB 长并且说要替换 50,000 "\n",用 string.Replace() 这将需要 36*50000MB 才能完成,这就是为什么会出现内存错误? gc 不应该在 aux1、aux2、aux3...等上执行,因为它们不再需要?
  • 这似乎不准确。 string.Replace 运行的本机 C++ 代码可在github.com/fixdpt/shared-source-cli-2.0/blob/master/clr/src/vm/… 获得。它首先迭代字符串,找到将被替换的子字符串的所有索引。然后它会根据它准确地分配正确的内存量。然后它再次迭代字符串,将原始字符串复制到新缓冲区,并在必要时进行替换。
【解决方案2】:

MSDN 跟随 StringBuilder:

大多数修改此类实例的方法都返回一个 引用同一个实例,您可以调用方法或属性 参考上。如果你想写一个单一的,这会很方便 链接连续操作的语句。

因此,当您使用 String 调用替换时,将分配新对象(大数据 - 36MB)以创建新字符串。但是 StringBuilder 访问相同的实例对象并且不会创建新的。

【讨论】:

    【解决方案3】:

    有一个内存压力的概念,意思是创建的临时对象越多,垃圾回收运行的频率就越高。

    所以: StringBuilder 创建的临时对象更少,内存压力也更小。

    StringBuilder Memory

    替换

    接下来我们使用 StringBuilder 来替换循环中的字符。首先将字符串转换为StringBuilder,然后调用StringBuilder的方法。这样更快——StringBuilder 类型在内部使用字符数组

    【讨论】:

      【解决方案4】:

      字符串在 C# 中是不可变的。如果使用 string.replace() 方法,系统将为每个替换创建一个 String 对象。 StringBuilder 类将帮助您避免创建对象。

      【讨论】:

        猜你喜欢
        • 2011-09-25
        • 2013-10-03
        • 1970-01-01
        • 2010-12-09
        • 2010-09-22
        • 2011-04-20
        • 2016-07-19
        • 2014-04-17
        • 2020-07-13
        相关资源
        最近更新 更多