【问题标题】:String Builder and string size字符串生成器和字符串大小
【发布时间】:2015-07-14 19:49:49
【问题描述】:

为什么 StringBuilder 的大小大于字符串(~250MB)。

请阅读问题。我想知道字符串中大小限制的原因,而不是 stringbuilder 中的原因。我已经修复了读取文件的问题。

是的,我知道有一些操作,我们可以对字符串生成器执行附加、替换、删除等操作。但是当我们无法从中获取 ToString() 并且我们无法编写时,它有什么用?它直接在文件中。我们必须让 ToString() 来实际使用它,但是因为它的大小超出了字符串范围,所以会抛出异常。

因此,当我将大约 1 gb 的文件读入字符串生成器但无法将其转换为字符串时,是否有任何使用大小大于字符串的字符串生成器。我阅读了 StringBuilder 优于 String 的所有优点和缺点,但我无法解释这一点

更新: 如果在块中读取,我想从文件中加载 XMLDocument,然后无法加载数据,因为根级节点需要其结束标记,该标记将位于其他块块中

更新: 我知道这不是一个正确的方法,现在我是不同的过程,但我仍然想知道字符串中大小限制的原因,而不是 stringbuilder 中的原因

更新: 我已经解决了我的问题,想知道stringbuilder没有内存限制的原因。

【问题讨论】:

  • 首先,您为什么还要将 1GB 文件加载到内存中?
  • 阅读this SO 线程。它说关于处理大型文本文件。在这种情况下,StringBuilder 似乎不是一个好的解决方案。
  • 您可以使用ToString(int,int) 生成更小的字符串。为什么你想把这么多的文本放在内存中呢?你想做什么? 比在 StringBuilder 中做所有事情更好的选择,例如使用内存映射文件、解析、使用文本生成器等
  • 这不是工作的正确工具,和/或不是解决问题的正确方法。
  • 这听起来像是XY Problem 的情况。你对 X 有问题,并假设 Y 是解决方案,所以当你遇到麻烦时,你问的是 Y 而不是 X。您要解决的实际问题是什么?

标签: c# string memory stringbuilder


【解决方案1】:

为什么 StringBuilder 的大小大于字符串(~250MB)。

原因取决于.net的版本。

Eric Lippert 在这里提到了两个实现:https://stackoverflow.com/a/6524401/360211

字符串生成器在内部维护char[]。当您追加时,它可能必须调整此数组的大小。为了停止每次追加时都需要调整它的大小,将其调整为更大的大小以预测未来的追加(实际上它的大小翻了一番)。所以StringBuilder 通常最终会比它的内容大,多达两倍。

较新的实现维护char[] 的链接列表。如果你做很多小的追加,链表的开销可能会占额外的 250MB。

在正常使用中,考虑到性能优势,字符串上的额外 100% 大小暂时不会产生任何影响,但是当您处理 GB 时,它变得很重要,这不是它的预期用途。

为什么你会得到OutOfMemoryException

链表实现比string 更适合内存,因为它不需要一个连续的1GB 块。当您ToString 时,它会强制它尝试查找另一个 GB,这也是连续的,这就是问题所在。

为什么没有约束阻止这一点?

嗯,有。约束是如果在ToString 期间没有足够的内存来创建string,则抛出OutOfMemoryException

您可能希望在Append 操作期间发生这种情况,但这无法确定。 StringBuilder 可以查看可用内存,但在您调用 ToString 之前,这可能会改变。所以StringBuilder 的作者可以设置一个任意的限制,但这不能同样适用于所有系统,因为有些系统会比其他系统拥有更多的内存。

您可能还想在调用ToString 之前执行减小StringBuilder 大小的操作,或者根本不调用ToString!因此,仅仅因为StringBuilderToString 太大,在任何时候都不是引发异常的理由。

【讨论】:

  • 如果不打算这样使用就不应该有任何限制
  • 那么设计师会在哪里划清界限?他们将如何在运行时执行它。您可能会遇到这样的情况,它在一天工作,然后代码必须处理仅比限制大一个字节的输入,然后抛出异常,这将是非常糟糕的。
  • 你在说什么设计师。谢谢,这是一个很好的解释,即字符串需要单个内存块。但是,这仍然不是问题的答案。当我们知道我们无法获得大数据时,那么这个字符串为什么会这么大
  • 编写StringBuilder代码的.net框架设计者。
  • “这不是问题的答案”你一直在改变你的问题!无论如何,我已经添加了答案。
【解决方案2】:

您可以尝试以下方法来处理大型 XML 文件。 CodeProject

【讨论】:

  • 我不想要读取 xml 文件的解决方案。我制作了一个新代码,可以非常有效地读取大文件,并将在短时间内分享。这里想知道stringbuilder没有内存限制的原因。
【解决方案3】:

您可以使用 StringBuilder.ToString(int, int) 从 StringBuilder 中获取更小的块大量内容。

此外,您可能需要考虑您是否真的使用了正确的工具来完成这项工作。 StringBuilder 的目的是构建和修改字符串,而不是将大文件加载到内存中。

【讨论】:

  • 我必须读取一个那么大的 xml 文件,如果我拆分该数据,则无法将其加载到 XMLDocument 中
  • @AmanSeth 您应该使用 XmlReader 而不是 XMLDocument。 XmlReader 使用 SAX 处理模式,读取出现在其输入流中的元素和属性。它不会将整个文件加载到内存中 - 事实上它可以轻松地处理网络流或任何类型的流
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-30
  • 2014-01-04
  • 1970-01-01
相关资源
最近更新 更多