C# 用于字符串连接的 StringBuilder 抛出 OutOfMemoryException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/363680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:37:59  来源:igfitidea点击:

StringBuilder for string concatenation throws OutOfMemoryException

c#out-of-memorystringbuilder

提问by rajesh pillai

We mostly tend to following the above best practice.

我们大多倾向于遵循上述最佳实践。

Have a look at String vs StringBuilder

看看String 与 StringBuilder

But StringBuilder could throw OutOfMemoryException even when there is sufficient memory available. It throws OOM exception because it needs "continuous block of memory".

即使有足够的可用内存,StringBuilder 也可能抛出OutOfMemoryException。它抛出 OOM 异常,因为它需要“连续的内存块”。

Some links for reference StringBuilder OutOfMemoryException

一些参考链接 StringBuilder OutOfMemoryException

and there are many more.....

还有更多......

How many of you faced this problem or aware and what did you do to resolve it?

你们中有多少人遇到或意识到了这个问题,你们做了什么来解决它?

Is there anything I am missing?

有什么我想念的吗?

P.S: I wasn't aware of this.

PS:我没有意识到这一点。

I have rephrased the question.

我已经改写了这个问题。

*** The same thing worked with manual concatenation(I'll verify this and update SO). The other thing that caused me concern was that there is enough memory in the system. That's the reason I raised this question here to check whether any one faced this problem or there was something drastically wrong with the code.

*** 同样的事情也适用于手动连接(我将验证这一点并更新 SO)。另一件让我担心的事情是系统中有足够的内存。这就是我在这里提出这个问题的原因,以检查是否有人遇到过这个问题,或者代码是否存在严重错误。

采纳答案by JaredPar

The underyling string you create will also need a contiguous block of memory because it is represented as an array of chars (arrays require contiguous memory) . If the StringBuilder throws an OOM exception you woludn't be able to build the underlying without it.

您创建的底层字符串还需要一个连续的内存块,因为它表示为字符数组(数组需要连续的内存)。如果 StringBuilder 抛出 OOM 异常,您将无法在没有它的情况下构建底层。

If creating a string causes an OOM, there is likely a more serious issue in your application.

如果创建字符串导致 OOM,则您的应用程序中可能存在更严重的问题。

Edit in response to clarification:

编辑以回应澄清:

There is a small subset of cases where building a string with a StringBuilder will fail when manual concatenation succeeds. Manual concatenation will use the exact length required in order to combine two strings while a StringBuilder has a different algorithmn for allocating memory. It's more aggressive and will likely allocate more memory than is actually needed for the string.

有一小部分情况,当手动连接成功时,使用 StringBuilder 构建字符串将失败。手动连接将使用组合两个字符串所需的确切长度,而 StringBuilder 具有用于分配内存的不同算法。它更具侵略性,并且可能会分配比字符串实际需要更多的内存。

Using a StringBuilder will also result in a temporary doubling of the memory required since the string will be present in a System.String form and StringBuilder simultaneously for a short time.

使用 StringBuilder 还会导致所需内存临时加倍,因为字符串将在短时间内同时以 System.String 形式和 StringBuilder 出现。

But if one way is causing an OOM and the other is not, it still likely points to a more serious issue in your program.

但是,如果一种方式导致 OOM 而另一种方式没有,则它仍然可能指向您的程序中存在更严重的问题。

回答by Kibbee

If you are running soclose to your memory limits that this is even a concern, then you should probably think about a different architecture or get a beefier machine.

如果您运行的内存限制如此之多以至于这甚至是一个问题,那么您可能应该考虑不同的架构或获得更强大的机器。

回答by arul

Well, the question actually is, why do you need to work with strings that long? If you stumble upon this problem, more than likely you should alter your concept.

好吧,问题实际上是,为什么需要使用那么长的字符串?如果您偶然发现这个问题,您很可能应该改变您的概念。

This problems affects even the System.Stringclass, so you should rather chunk your input into List< string>and process the data in parallel, which should increase overall performance if written properly.

这个问题甚至会影响System.String类,因此您应该将输入分块到List<string>并并行处理数据,如果写入正确,这应该会提高整体性能。

回答by TheSmurf

If StringBuilder is going to throw an OutOfMemoryException in your particular situation, then doing manual string concatenation is NOT a better solution; it's much worse. This is exactly the case (creating an extremely, extremely long string) where StringBuilder is supposed to be used. Manual concatenation of a string this large will take many times the memory that creation of a string with StringBuilder would take.

如果 StringBuilder 将在您的特定情况下抛出 OutOfMemoryException,那么手动字符串连接不是更好的解决方案;情况更糟。这正是应该使用 StringBuilder 的情况(创建一个非常长的字符串)。手动连接这么大的字符串将花费许多倍于使用 StringBuilder 创建字符串所需的内存。

That said, on a modern computer, if your string is running the computer out of contiguous memoryyour design is deeply, deeply flawed. I can't imagine what you could possibly doing that would create a string that large.

也就是说,在现代计算机上,如果您的字符串运行计算机的连续内存不足,则您的设计存在严重缺陷。我无法想象你可能会做什么会创建一个这么大的字符串。

回答by Lasse V. Karlsen

How much memory are we talking about? I'm not talking about free or total memory in the system, but how long is the string you're concatenating?

我们在谈论多少内存?我不是在谈论系统中的可用内存或总内存,而是你连接的字符串有多长?

A memory overflow exception is almost always a very bad sign about your code, even if it fails long before the memory actually runs out, like you've experienced due to continous memory not being available.

内存溢出异常几乎总是对您的代码非常不利的信号,即使它在内存实际耗尽之前很久就失败了,就像您由于连续内存不可用而经历的那样。

At that point you should really restructure the code.

那时你应该真正重构代码。

For instance, here are various ways to combat the problem:

例如,这里有多种解决问题的方法:

  1. Do not keep as much data in memory at one time, put it on disk or something
  2. Break it up, keep a list of string/stringbuilders and only add to them up to a certain length before switching to a new one, keeps the "continous memory" problem at bay
  3. Restructure the algorithm to not build up gigabyte of data in memory at all
  1. 不要一次在内存中保留尽可能多的数据,将其放在磁盘或其他东西上
  2. 打破它,保留一个字符串/字符串构建器的列表,并在切换到一个新的之前只将它们添加到一定长度,从而避免“连续内存”问题
  3. 重构算法以完全不在内存中建立千兆字节的数据

回答by Brian Rasmussen

If you look at how StringBuilderis implemented, you'll see that it actually uses a Stringto hold the data (Stringhas internal methods, that will allow StringBuilderto modify in place).

如果您查看如何StringBuilder实现,您会发现它实际上使用 aString来保存数据(String具有内部方法,可以StringBuilder就地修改)。

I.e. they both use the same amount of memory. However, since StringBuilderwill automatically extend the underlying array and copy as necessary when needed (but doubling the capacity) that is most likely the cause of the out of memory error. But as others have already pointed out both of the require a continuous block of memory,

即它们都使用相同数量的内存。但是,因为StringBuilder会在需要时自动扩展底层数组并根据需要进行复制(但将容量加倍),这很可能是导致内存不足错误的原因。但是正如其他人已经指出的那样,两者都需要一个连续的内存块,

回答by Erwin Mayer

I encountered this exception with very large strings built sucessively with different stringbuilders (which should not have caused a problem as they were declared within anonymous functions), and finally solved it by reusing a single StringBuilder, declared outside of the anonymous function.

我遇到了这个异常,它是用不同的字符串构建器连续构建的非常大的字符串(这应该不会引起问题,因为它们是在匿名函数中声明的),最后通过重用在匿名函数之外声明的单个 StringBuilder 解决了这个问题。

回答by archangel76

I had a very similar experience where I was appending strings but forgot to add the String.Format. Thus:

我有一个非常相似的经历,我在添加字符串但忘记添加 String.Format。因此:

myStringBuilder.Append("1,""{0}""", someVeryLargeIntVariable)

should have been:

本来应该:

myStringBuilder.Append(String.Format("1,""{0}""", someVeryLargeIntVariable))

Note that this is my vb.net code that failed. I replicated a similar test in c# with:

请注意,这是我失败的 vb.net 代码。我在 c# 中复制了一个类似的测试:

myStringBuilder.Append('a', 1564544656);

vs.

对比

myStringBuilder.Append(string.Format("1,\"{0}\"", 1564544656));

But in my case, vb.net got me in trouble b/c of the implicit conversions (I couldn't parallel the exactsame problem in c#).

但就我而言,vb.net 让我在隐式转换的 b/c 中遇到了麻烦(我无法在 c# 中解决完全相同的问题)。

I hope that helps someone.

我希望能帮助某人。